Support patch as input in image:copy

Add image:clear
This commit is contained in:
Lactozilla 2023-09-24 20:22:42 -03:00
parent f464297169
commit 46aebb7638
5 changed files with 308 additions and 34 deletions

View file

@ -90,7 +90,8 @@ enum patch {
// Methods
patch_getPixel,
patch_setPixel,
patch_copy
patch_copy,
patch_clear
};
static const char *const patch_opt[] = {
"valid",
@ -103,6 +104,7 @@ static const char *const patch_opt[] = {
"getPixel",
"setPixel",
"copy",
"clear",
NULL};
static int patch_fields_ref = LUA_NOREF;
@ -378,8 +380,17 @@ static int lib_patch_copy(lua_State *L)
int src_img_width = -1;
int src_img_height = -1;
patch_t *src_patch = NULL;
if (!lua_istable(L, 2))
return luaL_typerror(L, 2, "table");
{
src_patch = *((patch_t **)luaL_checkudata(L, 2, META_PATCH));
if (!src_patch)
return LUA_ErrInvalid(L, "patch_t");
src_img_width = src_patch->width;
src_img_height = src_patch->height;
}
else
{
src_img_width = luaL_optinteger(L, 3, patch->width);
@ -387,17 +398,17 @@ static int lib_patch_copy(lua_State *L)
lua_remove(L, 3);
lua_remove(L, 3);
}
if (src_img_width <= 0)
return luaL_error(L, "invalid source image width");
if (src_img_height <= 0)
return luaL_error(L, "invalid source image height");
if (src_img_width <= 0)
return luaL_error(L, "invalid source image width");
if (src_img_height <= 0)
return luaL_error(L, "invalid source image height");
}
int sx = luaL_optinteger(L, 3, 0);
int sy = luaL_optinteger(L, 4, 0);
int sw = luaL_optinteger(L, 5, patch->width);
int sh = luaL_optinteger(L, 6, patch->height);
int sw = luaL_optinteger(L, 5, src_img_width);
int sh = luaL_optinteger(L, 6, src_img_height);
int dx = luaL_optinteger(L, 7, 0);
int dy = luaL_optinteger(L, 8, 0);
boolean copy_transparent = lua_optboolean(L, 9);
@ -407,12 +418,12 @@ static int lib_patch_copy(lua_State *L)
if (sh <= 0)
return luaL_error(L, "invalid copy rect height");
size_t size = (unsigned)(src_img_width * src_img_height);
img_prepare_buffer(size);
if (lua_istable(L, 2))
{
size_t size = (unsigned)(src_img_width * src_img_height);
img_prepare_buffer(size);
if (lua_objlen(L, 2) + 1 != size)
return luaL_error(L, "invalid table length");
@ -422,9 +433,27 @@ static int lib_patch_copy(lua_State *L)
img_get_pixels_from_table(L, size);
lua_pop(L, 2);
Patch_UpdatePixels(patch, patch_update_buffer, src_img_width, src_img_height, PICFMT_FLAT16, sx, sy, sw, sh, dx, dy, copy_transparent);
}
else
{
V_DrawIntoPatch(patch, src_patch, dx << FRACBITS, dy << FRACBITS, FRACUNIT, FRACUNIT, 0, NULL, sx << FRACBITS, sy << FRACBITS, sw << FRACBITS, sh << FRACBITS, copy_transparent);
}
Patch_UpdatePixels(patch, patch_update_buffer, src_img_width, src_img_height, PICFMT_FLAT16, sx, sy, sw, sh, dx, dy, copy_transparent);
return 0;
}
static int lib_patch_clear(lua_State *L)
{
patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH));
if (!patch)
return LUA_ErrInvalid(L, "patch_t");
if (patch->type != PATCH_TYPE_DYNAMIC)
return luaL_error(L, "cannot modify a static patch");
Patch_Clear(patch);
return 0;
}
@ -471,6 +500,9 @@ static int patch_get(lua_State *L)
case patch_copy:
lua_pushcfunction(L, lib_patch_copy);
break;
case patch_clear:
lua_pushcfunction(L, lib_patch_clear);
break;
}
return 1;
}

View file

@ -19,7 +19,7 @@
#include "hardware/hw_glob.h"
#endif
static void Patch_MarkDirtyRect(dynamicpatch_t *dpatch, INT16 left, INT16 top, INT16 right, INT16 bottom);
static boolean Patch_CheckDirtyRect(dynamicpatch_t *dpatch);
static void Patch_ClearDirtyRect(dynamicpatch_t *dpatch);
patch_t *Patch_Create(INT16 width, INT16 height)
@ -51,8 +51,15 @@ patch_t *Patch_CreateDynamic(INT16 width, INT16 height)
return patch;
}
static void Patch_MarkDirtyRect(dynamicpatch_t *dpatch, INT16 left, INT16 top, INT16 right, INT16 bottom)
void Patch_MarkDirtyRect(patch_t *patch, INT16 left, INT16 top, INT16 right, INT16 bottom)
{
dynamicpatch_t *dpatch = (dynamicpatch_t*)patch;
left = max(0, left);
right = min(right, patch->width);
top = max(0, top);
bottom = min(bottom, patch->height);
if (left < dpatch->rect_dirty[0])
dpatch->rect_dirty[0] = left;
if (top < dpatch->rect_dirty[1])
@ -63,6 +70,37 @@ static void Patch_MarkDirtyRect(dynamicpatch_t *dpatch, INT16 left, INT16 top, I
dpatch->rect_dirty[3] = bottom;
}
static boolean Patch_CheckDirtyRect(dynamicpatch_t *dpatch)
{
patch_t *patch = (patch_t*)dpatch;
// left
if (dpatch->rect_dirty[0] < 0
|| dpatch->rect_dirty[0] > patch->width
|| dpatch->rect_dirty[0] >= dpatch->rect_dirty[2]) // right
return false;
// top
if (dpatch->rect_dirty[1] < 0
|| dpatch->rect_dirty[1] > patch->height
|| dpatch->rect_dirty[1] >= dpatch->rect_dirty[3]) // bottom
return false;
// right
if (dpatch->rect_dirty[2] > patch->width
|| dpatch->rect_dirty[2] < 0
|| dpatch->rect_dirty[2] <= dpatch->rect_dirty[0]) // left
return false;
// bottom
if (dpatch->rect_dirty[3] > patch->height
|| dpatch->rect_dirty[3] < 0
|| dpatch->rect_dirty[3] <= dpatch->rect_dirty[1]) // top
return false;
return true;
}
static void Patch_ClearDirtyRect(dynamicpatch_t *dpatch)
{
dpatch->rect_dirty[0] = INT16_MAX;
@ -83,6 +121,53 @@ static void Patch_InitDynamicColumns(patch_t *patch)
}
}
void Patch_Clear(patch_t *patch)
{
if (patch->type != PATCH_TYPE_DYNAMIC)
return;
size_t total_pixels = patch->width * patch->height;
memset(patch->pixels, 0, total_pixels * sizeof(UINT8));
for (INT32 x = 0; x < patch->width; x++)
patch->columns[x].num_posts = 0;
dynamicpatch_t *dpatch = (dynamicpatch_t*)patch;
memset(dpatch->pixels_opaque, 0, BIT_ARRAY_SIZE(total_pixels));
dpatch->is_dirty = dpatch->update_columns = true;
}
void Patch_ClearRect(patch_t *patch, INT16 x, INT16 y, INT16 width, INT16 height)
{
if (patch->type != PATCH_TYPE_DYNAMIC)
return;
dynamicpatch_t *dpatch = (dynamicpatch_t*)patch;
for (INT16 dy = y; dy < y + height; dy++)
{
if (dy < 0)
continue;
else if (dy >= patch->height)
break;
for (INT16 dx = x; dx < x + width; dx++)
{
if (dx < 0)
continue;
else if (dx >= patch->width)
break;
size_t position = (dx * patch->height) + dy;
unset_bit_array(dpatch->pixels_opaque, position);
dpatch->is_dirty = dpatch->update_columns = true;
}
}
}
patch_t *Patch_CreateFromDoomPatch(softwarepatch_t *source)
{
patch_t *patch = (patch_t*)Patch_Create(0, 0);
@ -337,16 +422,18 @@ void Patch_SetPixel(patch_t *patch, void *pixel, pictureformat_t informat, INT32
{
// No pixel in this position, so columns need to be rebuilt
if (!in_bit_array(dpatch->pixels_opaque, position))
{
set_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
}
set_bit_array(dpatch->pixels_opaque, position);
writePixelFunc(&patch->pixels[position], pixel);
dpatch->is_dirty = true;
}
if (dpatch->is_dirty)
Patch_MarkDirtyRect(dpatch, x, y, x + 1, y + 1);
Patch_MarkDirtyRect(patch, x, y, x + 1, y + 1);
}
void Patch_UpdatePixels(patch_t *patch,
@ -409,12 +496,7 @@ void Patch_UpdatePixels(patch_t *patch,
dynamicpatch_t *dpatch = (dynamicpatch_t *)patch;
INT32 dest_x1 = max(0, dx);
INT32 dest_x2 = min(dx + sw, patch->width);
INT32 dest_y1 = max(0, dy);
INT32 dest_y2 = min(dy + sh, patch->height);
Patch_MarkDirtyRect(dpatch, dest_x1, dest_y1, dest_x2, dest_y2);
Patch_MarkDirtyRect(patch, dx, dy, dx + sw, dy + sh);
for (INT32 x = dx; x < dx + sw; x++, sx++)
{
@ -453,9 +535,15 @@ void Patch_UpdatePixels(patch_t *patch,
}
else
{
set_bit_array(dpatch->pixels_opaque, position);
if (!in_bit_array(dpatch->pixels_opaque, position))
{
set_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
}
writePixelFunc(&patch->pixels[position], input);
dpatch->update_columns = dpatch->is_dirty = true;
dpatch->is_dirty = true;
}
}
}
@ -482,19 +570,22 @@ void Patch_DoDynamicUpdate(patch_t *patch)
if (patch->columns == NULL)
Patch_InitDynamicColumns(patch);
if (dpatch->update_columns)
if (Patch_CheckDirtyRect(dpatch))
{
for (INT32 x = dpatch->rect_dirty[0]; x < dpatch->rect_dirty[2]; x++)
Patch_RebuildColumn(&patch->columns[x], x, patch->height, dpatch->pixels_opaque);
if (dpatch->update_columns)
{
for (INT32 x = dpatch->rect_dirty[0]; x < dpatch->rect_dirty[2]; x++)
Patch_RebuildColumn(&patch->columns[x], x, patch->height, dpatch->pixels_opaque);
}
#ifdef HWRENDER
if (patch->hardware)
HWR_UpdatePatchRegion(patch, dpatch->rect_dirty[0], dpatch->rect_dirty[1], dpatch->rect_dirty[2], dpatch->rect_dirty[3]);
#endif
}
Patch_FreeMiscData(patch);
#ifdef HWRENDER
if (patch->hardware)
HWR_UpdatePatchRegion(patch, dpatch->rect_dirty[0], dpatch->rect_dirty[1], dpatch->rect_dirty[2], dpatch->rect_dirty[3]);
#endif
dpatch->is_dirty = false;
dpatch->update_columns = false;

View file

@ -37,6 +37,10 @@ void Patch_UpdatePixels(patch_t *patch,
boolean Patch_NeedsUpdate(patch_t *patch);
void Patch_DoDynamicUpdate(patch_t *patch);
void Patch_MarkDirtyRect(patch_t *dpatch, INT16 left, INT16 top, INT16 right, INT16 bottom);
void Patch_Clear(patch_t *patch);
void Patch_ClearRect(patch_t *patch, INT16 x, INT16 y, INT16 width, INT16 height);
bitarray_t *Patch_GetOpaqueRegions(patch_t *patch);

View file

@ -1064,6 +1064,152 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
}
}
void V_DrawIntoPatch(patch_t *dest_patch, patch_t *src_patch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 flags, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h, boolean copy_transparent)
{
if (dest_patch->type != PATCH_TYPE_DYNAMIC)
return;
dynamicpatch_t *dpatch = (dynamicpatch_t *)dest_patch;
if (Patch_NeedsUpdate(src_patch))
Patch_DoDynamicUpdate(src_patch);
if (src_patch->columns == NULL)
return;
if (sx < 0)
{
w += sx;
sx = 0;
}
if (sy < 0)
{
h += sy;
sy = 0;
}
if (sx >= src_patch->width << FRACBITS || w <= 0)
return;
if (sy >= src_patch->height << FRACBITS || h <= 0)
return;
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t) = standardpdraw;
v_translevel = NULL;
v_colormap = NULL;
UINT32 alphalevel = ((flags & V_ALPHAMASK) >> V_ALPHASHIFT);
UINT32 blendmode = ((flags & V_BLENDMASK) >> V_BLENDSHIFT);
if (alphalevel || blendmode)
{
if (alphalevel >= 10)
return; // invis
if (alphalevel || blendmode)
{
v_translevel = R_GetBlendTable(blendmode+1, alphalevel);
patchdrawfunc = translucentpdraw;
}
}
if (colormap)
{
v_colormap = colormap;
patchdrawfunc = v_translevel ? transmappedpdraw : mappedpdraw;
}
fixed_t fdup = pscale;
fixed_t vdup = vscale;
fixed_t colfrac = FixedDiv(FRACUNIT, fdup);
fixed_t rowfrac = FixedDiv(FRACUNIT, vdup);
fixed_t offsetx = 0, offsety = 0;
// left offset
if (flags & V_FLIP)
offsetx = FixedMul((src_patch->width - src_patch->leftoffset)<<FRACBITS, pscale) + 1;
else
offsetx = FixedMul(src_patch->leftoffset<<FRACBITS, pscale);
// top offset
offsety = FixedMul(src_patch->topoffset<<FRACBITS, vscale);
// Subtract the offsets from x/y positions
x -= offsetx;
y -= offsety;
x >>= FRACBITS;
y >>= FRACBITS;
fixed_t pwidth = src_patch->width;
if (pscale != FRACUNIT)
pwidth = (pwidth * pscale) >> FRACBITS;
int dest_x = x;
Patch_MarkDirtyRect(dest_patch, x, y, x + (w >> FRACBITS), y + (h >> FRACBITS));
if (copy_transparent)
Patch_ClearRect(dest_patch, x, y, w >> FRACBITS, h >> FRACBITS);
if (dest_patch->pixels == NULL)
dest_patch->pixels = Z_Calloc(dest_patch->width * dest_patch->height, PU_PATCH_DATA, NULL);
for (fixed_t col = sx; (col>>FRACBITS) < src_patch->width && (col - sx) < w; col += colfrac, dest_x++)
{
if (dest_x < 0)
continue;
else if (dest_x >= dest_patch->width)
break;
unsigned texturecolumn = col >> FRACBITS;
if (flags & V_FLIP)
texturecolumn = src_patch->width - 1 - texturecolumn;
column_t *column = &src_patch->columns[texturecolumn];
for (unsigned i = 0; i < column->num_posts; i++)
{
post_t *post = &column->posts[i];
INT32 topdelta = post->topdelta << FRACBITS;
UINT8 *source = column->pixels + post->data_offset;
int dest_y = y;
fixed_t ofs;
if (topdelta - sy > 0)
{
dest_y = y + FixedInt(FixedMul(topdelta - sy, vdup));
ofs = 0;
}
else
ofs = sy - topdelta;
for (; dest_y < dest_patch->height && (size_t)(ofs>>FRACBITS) < post->length && ((ofs - sy) + topdelta) < h; ofs += rowfrac, dest_y++)
{
if (dest_y < 0)
continue;
size_t position = (dest_x * dest_patch->height) + dest_y;
if (!in_bit_array(dpatch->pixels_opaque, position))
{
set_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
}
UINT8 *dest = &dest_patch->pixels[position];
*dest = patchdrawfunc(dest, source, ofs);
dpatch->is_dirty = true;
}
if (dest_y >= dest_patch->height)
break;
}
}
}
//
// V_DrawContinueIcon
// Draw a mini player! If we can, that is. Otherwise we draw a star.

View file

@ -172,6 +172,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_DrawFixedPatch(x,y,sc,s,p,c) V_DrawStretchyFixedPatch(x,y,sc,sc,s,p,c)
void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap);
void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
void V_DrawIntoPatch(patch_t *dest_patch, patch_t *src_patch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 flags, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h, boolean copy_transparent);
void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor);