Implement RGBA image creation (WIP)

This commit is contained in:
Lactozilla 2023-10-31 01:04:31 -03:00
parent 6d5f5a5247
commit 379c163bef
10 changed files with 935 additions and 441 deletions

View file

@ -272,7 +272,6 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
fixed_t scale_y = FRACUNIT;
INT32 bpp = format2bpp(mipmap->format);
if (bpp < 1 || bpp > 4)
I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp);
@ -294,6 +293,39 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
}
}
static void HWR_DrawPatchInCacheRGBA(GLMipmap_t *mipmap,
INT32 pblockwidth, INT32 pblockheight,
INT32 pwidth, INT32 pheight,
const patch_t *realpatch)
{
if (pwidth <= 0 || pheight <= 0)
return;
INT32 bpp = format2bpp(mipmap->format);
if (bpp != 4)
I_Error("HWR_DrawPatchInCacheRGBA: invalid bpp (%d)\n",bpp);
fixed_t stepx = (pwidth << FRACBITS) / pblockwidth;
fixed_t stepy = (pheight << FRACBITS) / pblockheight;
fixed_t posy = 0;
RGBA_t *block = (RGBA_t*)mipmap->data;
const RGBA_t *source = (RGBA_t*)realpatch->pixels;
for (int j = 0; j < pblockheight; j++)
{
fixed_t posx = 0;
RGBA_t *dest = &block[j * mipmap->width];
for (int i = 0; i < pblockwidth; i++)
{
size_t position = ((posx >> FRACBITS) * pheight) + (posy >> FRACBITS);
*dest++ = source[position];
posx += stepx;
}
posy += stepy;
}
}
// This function we use for caching patches that belong to textures
static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
INT32 pblockwidth, INT32 pblockheight,
@ -539,10 +571,10 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm
{
MakeBlock(grMipmap);
HWR_DrawPatchInCache(grMipmap,
grMipmap->width, grMipmap->height,
patch->width, patch->height,
patch);
if (patch->format == PATCH_FORMAT_RGBA)
HWR_DrawPatchInCacheRGBA(grMipmap, grMipmap->width, grMipmap->height, patch->width, patch->height, patch);
else
HWR_DrawPatchInCache(grMipmap, grMipmap->width, grMipmap->height, patch->width, patch->height, patch);
}
}
@ -942,16 +974,43 @@ static void HWR_UpdatePatchPixels(GLMipmap_t *mipmap, UINT8 *pixels, INT16 patch
}
}
static void HWR_UpdatePatchPixelsRGBA(GLMipmap_t *mipmap, RGBA_t *pixels, INT16 patchheight, INT16 left, INT16 top, INT16 right, INT16 bottom)
{
INT32 bpp = format2bpp(mipmap->format);
if (bpp != 4)
I_Error("HWR_UpdatePatchPixelsRGBA: invalid bpp (%d)\n",bpp);
UINT8 *dest_pixels = (UINT8*)mipmap->data;
for (INT16 y = top; y < bottom; y++)
{
UINT8 *dest = &dest_pixels[(y * (mipmap->width * bpp)) + (left * bpp)];
for (INT16 x = left; x < right; x++)
{
RGBA_t texel = pixels[(x * patchheight) + y];
memcpy(dest, &texel, sizeof(RGBA_t));
dest += bpp;
}
}
}
static void HWR_UpdateMipmapRegion(patch_t *patch, GLMipmap_t *grMipmap, INT16 left, INT16 top, INT16 right, INT16 bottom)
{
GLPatch_t *grPatch = patch->hardware;
bitarray_t *pixels_opaque = Patch_GetOpaqueRegions(patch);
if (pixels_opaque == NULL || grMipmap->width == 0 || grMipmap->data == NULL)
if (grMipmap->width == 0 || grMipmap->data == NULL || patch->type == PATCH_TYPE_STATIC)
HWR_MakePatch(patch, grPatch, grMipmap, true);
else
HWR_UpdatePatchPixels(grMipmap, patch->pixels, patch->height, pixels_opaque, left, top, right, bottom);
{
if (patch->format == PATCH_FORMAT_RGBA)
HWR_UpdatePatchPixelsRGBA(grMipmap, (RGBA_t*)patch->pixels, patch->width, left, top, right, bottom);
else
{
bitarray_t *pixels_opaque = Patch_GetOpaqueRegions(patch);
HWR_UpdatePatchPixels(grMipmap, patch->pixels, patch->height, pixels_opaque, left, top, right, bottom);
}
}
// If hardware does not have the texture, then call pfnSetTexture to upload it
// If it does have the texture, then call pfnUpdateTextureRegion to update it

View file

@ -24,6 +24,7 @@
#include "../m_misc.h" //FIL_WriteFile()
#include "../r_draw.h" //viewborderlump
#include "../r_main.h"
#include "../r_patch.h"
#include "../w_wad.h"
#include "../z_zone.h"
#include "../v_video.h"
@ -81,6 +82,9 @@ void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option)
float sdup = FIXED_TO_FLOAT(vid.fdup)*2.0f;
float pdup = FIXED_TO_FLOAT(vid.fdup)*2.0f;
if (Patch_NeedsUpdate(gpatch, false))
Patch_DoDynamicUpdate(gpatch, false);
// make patch ready in hardware cache
HWR_GetPatch(gpatch);
hwrPatch = ((GLPatch_t *)gpatch->hardware);
@ -138,6 +142,9 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
UINT8 perplayershuffle = 0;
if (Patch_NeedsUpdate(gpatch, false))
Patch_DoDynamicUpdate(gpatch, false);
// make patch ready in hardware cache
if (!colormap)
HWR_GetPatch(gpatch);
@ -380,6 +387,9 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
UINT8 perplayershuffle = 0;
if (Patch_NeedsUpdate(gpatch, false))
Patch_DoDynamicUpdate(gpatch, false);
// make patch ready in hardware cache
if (!colormap)
HWR_GetPatch(gpatch);

View file

@ -301,6 +301,11 @@ static int lib_patch_getPixel(lua_State *L)
void *pixel = Patch_GetPixel(patch, x, y);
if (pixel == NULL)
lua_pushnil(L);
else if (patch->format == PATCH_FORMAT_RGBA)
{
UINT32 px = *(UINT32 *)pixel;
lua_pushinteger(L, px);
}
else
{
UINT8 px = *(UINT8 *)pixel;
@ -320,30 +325,40 @@ static int lib_patch_setPixel(lua_State *L)
int y = luaL_checkinteger(L, 3);
int color = luaL_checkinteger(L, 4);
UINT16 pixel = 0x0000;
if (color >= 0 && color <= 0xFF)
pixel = 0xFF00 | (UINT8)color;
if (patch->format == PATCH_FORMAT_RGBA)
{
UINT32 pixel = (UINT32)color;
Patch_SetPixel(patch, &pixel, PICFMT_FLAT32, x, y, true);
}
else
{
UINT16 pixel = 0x0000;
if (color >= 0 && color <= 0xFF)
pixel = 0xFF00 | (UINT8)color;
Patch_SetPixel(patch, &pixel, PICFMT_FLAT16, x, y, true);
Patch_SetPixel(patch, &pixel, PICFMT_FLAT16, x, y, true);
}
return 0;
}
static UINT16 *patch_update_buffer = NULL;
static void *patch_update_buffer = NULL;
static size_t patch_update_buffer_size = 0;
static void img_prepare_buffer(size_t size)
{
if (size > patch_update_buffer_size)
{
patch_update_buffer = Z_Realloc(patch_update_buffer, size * sizeof(UINT16), PU_STATIC, NULL);
patch_update_buffer = Z_Realloc(patch_update_buffer, size, PU_STATIC, NULL);
patch_update_buffer_size = size;
}
}
static void img_get_pixels_from_table(lua_State *L, size_t size)
{
memset(patch_update_buffer, 0, patch_update_buffer_size);
UINT16 *buf = (UINT16 *)patch_update_buffer;
memset(buf, 0, patch_update_buffer_size);
for (size_t i = 0; i < size; i++)
{
@ -362,9 +377,30 @@ static void img_get_pixels_from_table(lua_State *L, size_t size)
}
if (pal_idx != -1)
patch_update_buffer[i] = 0xFF00 | (UINT8)pal_idx;
buf[i] = 0xFF00 | (UINT8)pal_idx;
else
patch_update_buffer[i] = 0x0000;
buf[i] = 0x0000;
}
}
static void img_get_rgba_pixels_from_table(lua_State *L, size_t size)
{
UINT32 *buf = (UINT32 *)patch_update_buffer;
memset(buf, 0, patch_update_buffer_size);
for (size_t i = 0; i < size; i++)
{
UINT32 color = 0;
if (lua_next(L, -2) != 0)
{
if (lua_isnumber(L,-1))
color = (UINT32)luaL_checkinteger(L, -1);
lua_pop(L, 1);
}
buf[i] = color;
}
}
@ -422,23 +458,41 @@ static int lib_patch_copy(lua_State *L)
{
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");
lua_pushvalue(L, 2);
lua_pushnil(L);
img_get_pixels_from_table(L, size);
int format;
if (patch->format == PATCH_FORMAT_RGBA)
{
img_prepare_buffer(size * 4);
img_get_rgba_pixels_from_table(L, size);
format = PICFMT_FLAT32;
}
else
{
img_prepare_buffer(size * 2);
img_get_pixels_from_table(L, size);
format = PICFMT_FLAT16;
}
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);
Patch_UpdatePixels(patch, patch_update_buffer, src_img_width, src_img_height, format, 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);
if (patch->format == PATCH_FORMAT_RGBA)
{
// Unimplemented
}
else
V_DrawIntoPatch(patch, src_patch, dx << FRACBITS, dy << FRACBITS, FRACUNIT, FRACUNIT, 0, NULL, sx << FRACBITS, sy << FRACBITS, sw << FRACBITS, sh << FRACBITS, copy_transparent);
}
return 0;
@ -665,15 +719,40 @@ static int camera_set(lua_State *L)
}
// Image lib
enum patch_fmt {
patch_fmt_palette,
patch_fmt_rgba
};
static const char *const patch_fmt_opt[] = {
"palette",
"rgba",
NULL};
static int lib_image_create(lua_State *L)
{
int w = luaL_checkinteger(L, 1);
int h = luaL_checkinteger(L, 2);
enum patch_fmt fmt = luaL_checkoption(L, 3, "palette", patch_fmt_opt);
if (w <= 0)
return luaL_error(L, "invalid image width %d", w);
if (h <= 0)
return luaL_error(L, "invalid image width %d", h);
LUA_PushUserdata(L, Patch_CreateDynamic(w, h), META_PATCH);
UINT8 format = 0;
switch(fmt)
{
case patch_fmt_palette:
format = PATCH_FORMAT_PALETTE;
break;
case patch_fmt_rgba:
format = PATCH_FORMAT_RGBA;
break;
}
LUA_PushUserdata(L, Patch_CreateDynamic(w, h, format), META_PATCH);
return 1;
}

View file

@ -810,6 +810,7 @@ typedef struct
typedef struct
{
UINT8 type;
UINT8 format;
INT16 width, height;
INT16 leftoffset, topoffset;
@ -841,6 +842,7 @@ typedef struct
boolean update_columns;
INT16 rect_dirty[4]; // left, top, right, bottom
INT16 column_dirty[2]; // left, right
bitarray_t *pixels_opaque;
} dynamicpatch_t;

View file

@ -22,6 +22,9 @@
static boolean Patch_CheckDirtyRect(dynamicpatch_t *dpatch);
static void Patch_ClearDirtyRect(dynamicpatch_t *dpatch);
static boolean Patch_CheckDirtyColumns(dynamicpatch_t *dpatch);
static void Patch_ClearDirtyColumns(dynamicpatch_t *dpatch);
patch_t *Patch_Create(INT16 width, INT16 height)
{
patch_t *patch = Z_Calloc(sizeof(staticpatch_t), PU_PATCH, NULL);
@ -29,24 +32,31 @@ patch_t *Patch_Create(INT16 width, INT16 height)
patch->width = width;
patch->height = height;
patch->type = PATCH_TYPE_STATIC;
patch->format = PATCH_FORMAT_PALETTE;
return patch;
}
patch_t *Patch_CreateDynamic(INT16 width, INT16 height)
patch_t *Patch_CreateDynamic(INT16 width, INT16 height, UINT8 format)
{
patch_t *patch = Z_Calloc(sizeof(dynamicpatch_t), PU_PATCH, NULL);
patch->width = width;
patch->height = height;
patch->type = PATCH_TYPE_DYNAMIC;
patch->format = format;
dynamicpatch_t *dpatch = (dynamicpatch_t*)patch;
dpatch->pixels_opaque = Z_Calloc(BIT_ARRAY_SIZE(width * height), PU_PATCH_DATA, NULL);
dpatch->is_dirty = false;
dpatch->update_columns = false;
if (format == PATCH_FORMAT_PALETTE)
dpatch->pixels_opaque = Z_Calloc(BIT_ARRAY_SIZE(width * height), PU_PATCH_DATA, NULL);
else if (format == PATCH_FORMAT_RGBA)
patch->pixels = Z_Calloc(patch->width * patch->height * Patch_GetBpp(patch), PU_PATCH_DATA, NULL);
Patch_ClearDirtyRect(dpatch);
Patch_ClearDirtyColumns(dpatch);
return patch;
}
@ -68,6 +78,11 @@ void Patch_MarkDirtyRect(patch_t *patch, INT16 left, INT16 top, INT16 right, INT
dpatch->rect_dirty[2] = right;
if (bottom > dpatch->rect_dirty[3])
dpatch->rect_dirty[3] = bottom;
if (left < dpatch->column_dirty[0])
dpatch->column_dirty[0] = left;
if (right > dpatch->column_dirty[1])
dpatch->column_dirty[1] = right;
}
static boolean Patch_CheckDirtyRect(dynamicpatch_t *dpatch)
@ -109,15 +124,42 @@ static void Patch_ClearDirtyRect(dynamicpatch_t *dpatch)
dpatch->rect_dirty[3] = INT16_MIN;
}
static boolean Patch_CheckDirtyColumns(dynamicpatch_t *dpatch)
{
patch_t *patch = (patch_t*)dpatch;
// left
if (dpatch->column_dirty[0] < 0
|| dpatch->column_dirty[0] > patch->width
|| dpatch->column_dirty[0] >= dpatch->column_dirty[1]) // right
return false;
// right
if (dpatch->column_dirty[1] > patch->width
|| dpatch->column_dirty[1] < 0
|| dpatch->column_dirty[1] <= dpatch->column_dirty[0]) // left
return false;
return true;
}
static void Patch_ClearDirtyColumns(dynamicpatch_t *dpatch)
{
dpatch->column_dirty[0] = INT16_MAX;
dpatch->column_dirty[1] = INT16_MIN;
}
static void Patch_InitDynamicColumns(patch_t *patch)
{
if (patch->columns == NULL)
patch->columns = Z_Calloc(sizeof(column_t) * patch->width, PU_PATCH_DATA, NULL);
size_t bpp = Patch_GetBpp(patch);
for (INT32 x = 0; x < patch->width; x++)
{
column_t *column = &patch->columns[x];
column->pixels = &patch->pixels[patch->height * x];
column->pixels = &patch->pixels[patch->height * x * bpp];
}
}
@ -130,12 +172,16 @@ void Patch_Clear(patch_t *patch)
memset(patch->pixels, 0, total_pixels * sizeof(UINT8));
for (INT32 x = 0; x < patch->width; x++)
patch->columns[x].num_posts = 0;
if (patch->columns)
{
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));
if (dpatch->pixels_opaque)
memset(dpatch->pixels_opaque, 0, BIT_ARRAY_SIZE(total_pixels));
dpatch->is_dirty = dpatch->update_columns = true;
}
@ -162,7 +208,16 @@ void Patch_ClearRect(patch_t *patch, INT16 x, INT16 y, INT16 width, INT16 height
break;
size_t position = (dx * patch->height) + dy;
unset_bit_array(dpatch->pixels_opaque, position);
if (patch->format == PATCH_FORMAT_RGBA)
{
UINT32 *pixels = (UINT32 *)patch->pixels;
pixels[position] = 0;
}
else if (dpatch->pixels_opaque)
{
unset_bit_array(dpatch->pixels_opaque, position);
}
dpatch->is_dirty = dpatch->update_columns = true;
}
}
@ -266,21 +321,47 @@ void Patch_MakeColumns(softwarepatch_t *source, size_t num_columns, INT16 width,
// Other functions
//
static void Patch_RebuildColumn(column_t *column, INT32 x, INT16 height, bitarray_t *is_opaque)
unsigned Patch_GetBpp(patch_t *patch)
{
if (patch->format == PATCH_FORMAT_RGBA)
return 4;
else
return 1;
}
static void Patch_RebuildColumn(patch_t *patch, INT32 x, bitarray_t *is_opaque)
{
post_t *post = NULL;
boolean was_opaque = false;
column_t *column = &patch->columns[x];
INT16 height = patch->height;
size_t bpp = Patch_GetBpp(patch);
unsigned post_count = column->num_posts;
column->num_posts = 0;
for (INT32 y = 0; y < height; y++)
{
size_t position = (x * height) + y;
// End span if we have a transparent pixel
if (!in_bit_array(is_opaque, (x * height) + y))
if (patch->format == PATCH_FORMAT_RGBA)
{
was_opaque = false;
continue;
UINT32 *pixels = (UINT32 *)patch->pixels;
if (R_GetRgbaA(pixels[position]) == 0)
{
was_opaque = false;
continue;
}
}
else
{
if (!in_bit_array(is_opaque, position))
{
was_opaque = false;
continue;
}
}
if (!was_opaque)
@ -296,7 +377,7 @@ static void Patch_RebuildColumn(column_t *column, INT32 x, INT16 height, bitarra
post = &column->posts[column->num_posts - 1];
post->topdelta = (unsigned)y;
post->length = 0;
post->data_offset = post->topdelta;
post->data_offset = post->topdelta * bpp;
}
was_opaque = true;
@ -323,21 +404,30 @@ void *Patch_GetPixel(patch_t *patch, INT32 x, INT32 y)
if (x < 0 || x >= patch->width || y < 0 || y >= patch->height)
return NULL;
if (Patch_NeedsUpdate(patch))
Patch_DoDynamicUpdate(patch);
if (Patch_NeedsUpdate(patch, true))
Patch_DoDynamicUpdate(patch, true);
if (patch->columns == NULL)
return NULL;
bitarray_t *pixels_opaque = Patch_GetOpaqueRegions(patch);
if (pixels_opaque)
if (patch->format == PATCH_FORMAT_RGBA)
{
// Well, that makes it easy
size_t position = (x * patch->height) + y;
if (!in_bit_array(pixels_opaque, position))
return &patch->pixels[position * 4];
}
else
{
if (patch->columns == NULL)
return NULL;
return &patch->pixels[position];
bitarray_t *pixels_opaque = Patch_GetOpaqueRegions(patch);
if (pixels_opaque)
{
size_t position = (x * patch->height) + y;
if (!in_bit_array(pixels_opaque, position))
return NULL;
return &patch->pixels[position];
}
}
column_t *column = &patch->columns[x];
@ -384,12 +474,25 @@ void Patch_SetPixel(patch_t *patch, void *pixel, pictureformat_t informat, INT32
return;
void *(*writePixelFunc)(void *, void *) = NULL;
if (inbpp == PICDEPTH_32BPP)
writePixelFunc = PicFmt_WritePixel_i32o8;
else if (inbpp == PICDEPTH_16BPP)
writePixelFunc = PicFmt_WritePixel_i16o8;
else if (inbpp == PICDEPTH_8BPP)
writePixelFunc = PicFmt_WritePixel_i8o8;
if (patch->format == PATCH_FORMAT_RGBA)
{
if (inbpp == PICDEPTH_32BPP)
writePixelFunc = PicFmt_WritePixel_i32o32;
else if (inbpp == PICDEPTH_16BPP)
writePixelFunc = PicFmt_WritePixel_i16o32;
else if (inbpp == PICDEPTH_8BPP)
writePixelFunc = PicFmt_WritePixel_i8o32;
}
else
{
if (inbpp == PICDEPTH_32BPP)
writePixelFunc = PicFmt_WritePixel_i32o8;
else if (inbpp == PICDEPTH_16BPP)
writePixelFunc = PicFmt_WritePixel_i16o8;
else if (inbpp == PICDEPTH_8BPP)
writePixelFunc = PicFmt_WritePixel_i8o8;
}
// If the patch is empty
if (!patch->pixels)
@ -401,35 +504,65 @@ void Patch_SetPixel(patch_t *patch, void *pixel, pictureformat_t informat, INT32
}
if (patch->pixels == NULL)
patch->pixels = Z_Calloc(patch->width * patch->height, PU_PATCH_DATA, NULL);
patch->pixels = Z_Calloc(patch->width * patch->height * Patch_GetBpp(patch), PU_PATCH_DATA, NULL);
}
dynamicpatch_t *dpatch = (dynamicpatch_t *)patch;
size_t position = (x * patch->height) + y;
if (!pixel_is_opaque)
if (patch->format == PATCH_FORMAT_RGBA)
{
if (transparent_overwrite)
size_t position = (x * patch->height) + y;
RGBA_t *dest = (RGBA_t*)(&patch->pixels[position * 4]);
if (!pixel_is_opaque)
{
// No longer a pixel in this position, so columns need to be rebuilt
unset_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
if (transparent_overwrite)
{
// No longer a pixel in this position, so columns need to be rebuilt
dest->s.alpha = 0;
dpatch->update_columns = true;
dpatch->is_dirty = true;
}
}
else
{
// No pixel in this position, so columns need to be rebuilt
if (dest->s.alpha == 0)
dpatch->update_columns = true;
writePixelFunc(dest, pixel);
dpatch->is_dirty = true;
}
}
else
{
// No pixel in this position, so columns need to be rebuilt
if (!in_bit_array(dpatch->pixels_opaque, position))
size_t position = (x * patch->height) + y;
if (!pixel_is_opaque)
{
set_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
if (transparent_overwrite)
{
// No longer a pixel in this position, so columns need to be rebuilt
unset_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
dpatch->is_dirty = true;
}
}
else
{
// 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;
}
writePixelFunc(&patch->pixels[position], pixel);
writePixelFunc(&patch->pixels[position], pixel);
dpatch->is_dirty = true;
dpatch->is_dirty = true;
}
}
if (dpatch->is_dirty)
@ -449,7 +582,7 @@ void Patch_UpdatePixels(patch_t *patch,
return;
if (patch->pixels == NULL)
patch->pixels = Z_Calloc(patch->width * patch->height, PU_PATCH_DATA, NULL);
patch->pixels = Z_Calloc(patch->width * patch->height * Patch_GetBpp(patch), PU_PATCH_DATA, NULL);
void *(*readPixelFunc)(void *, pictureformat_t, INT32, INT32, INT32, INT32, pictureflags_t) = NULL;
UINT8 (*getAlphaFunc)(void *, pictureflags_t) = NULL;
@ -475,20 +608,41 @@ void Patch_UpdatePixels(patch_t *patch,
}
}
switch (Picture_FormatBPP(informat))
if (patch->format == PATCH_FORMAT_RGBA)
{
case PICDEPTH_32BPP:
getAlphaFunc = PicFmt_GetAlpha_32bpp;
writePixelFunc = PicFmt_WritePixel_i32o8;
break;
case PICDEPTH_16BPP:
getAlphaFunc = PicFmt_GetAlpha_16bpp;
writePixelFunc = PicFmt_WritePixel_i16o8;
break;
case PICDEPTH_8BPP:
getAlphaFunc = PicFmt_GetAlpha_8bpp;
writePixelFunc = PicFmt_WritePixel_i8o8;
break;
switch (Picture_FormatBPP(informat))
{
case PICDEPTH_32BPP:
getAlphaFunc = PicFmt_GetAlpha_32bpp;
writePixelFunc = PicFmt_WritePixel_i32o32;
break;
case PICDEPTH_16BPP:
getAlphaFunc = PicFmt_GetAlpha_16bpp;
writePixelFunc = PicFmt_WritePixel_i16o32;
break;
case PICDEPTH_8BPP:
getAlphaFunc = PicFmt_GetAlpha_8bpp;
writePixelFunc = PicFmt_WritePixel_i8o32;
break;
}
}
else
{
switch (Picture_FormatBPP(informat))
{
case PICDEPTH_32BPP:
getAlphaFunc = PicFmt_GetAlpha_32bpp;
writePixelFunc = PicFmt_WritePixel_i32o8;
break;
case PICDEPTH_16BPP:
getAlphaFunc = PicFmt_GetAlpha_16bpp;
writePixelFunc = PicFmt_WritePixel_i16o8;
break;
case PICDEPTH_8BPP:
getAlphaFunc = PicFmt_GetAlpha_8bpp;
writePixelFunc = PicFmt_WritePixel_i8o8;
break;
}
}
if (readPixelFunc == NULL || writePixelFunc == NULL || getAlphaFunc == NULL)
@ -498,67 +652,120 @@ void Patch_UpdatePixels(patch_t *patch,
Patch_MarkDirtyRect(patch, dx, dy, dx + sw, dy + sh);
for (INT32 x = dx; x < dx + sw; x++, sx++)
if (patch->format == PATCH_FORMAT_RGBA)
{
if (x < 0 || sx < 0)
continue;
else if (x >= patch->width || sx >= src_img_width)
break;
INT32 src_y = sy;
for (INT32 y = dy; y < dy + sh; y++, src_y++)
for (INT32 y = dy; y < dy + sh; y++, sy++)
{
if (y < 0 || src_y < 0)
if (y < 0 || sy < 0)
continue;
else if (y >= patch->height || src_y >= src_img_height)
else if (y >= patch->height || sy >= src_img_height)
break;
boolean opaque = false;
INT32 src_x = sx;
// Read pixel
void *input = readPixelFunc(pixels, informat, sx, src_y, src_img_width, src_img_height, 0);
// Determine opacity
if (input != NULL)
opaque = getAlphaFunc(input, 0) > 0;
size_t position = (x * patch->height) + y;
if (!opaque)
for (INT32 x = dx; x < dx + sw; x++, src_x++)
{
if (transparent_overwrite)
if (x < 0 || src_x < 0)
continue;
else if (x >= patch->width || src_x >= src_img_width)
break;
boolean opaque = false;
// Read pixel
void *input = readPixelFunc(pixels, informat, src_x, sy, src_img_width, src_img_height, 0);
// Determine opacity
if (input != NULL)
opaque = getAlphaFunc(input, 0) > 0;
size_t position = (x * patch->height) + y;
RGBA_t *dest = (RGBA_t*)(&patch->pixels[position * 4]);
if (!opaque)
{
unset_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = dpatch->is_dirty = true;
if (transparent_overwrite)
{
dest->s.alpha = 0;
dpatch->update_columns = dpatch->is_dirty = true;
}
}
else
{
if (dest->s.alpha == 0)
dpatch->update_columns = true;
writePixelFunc(dest, input);
dpatch->is_dirty = true;
}
}
else
}
}
else
{
for (INT32 x = dx; x < dx + sw; x++, sx++)
{
if (x < 0 || sx < 0)
continue;
else if (x >= patch->width || sx >= src_img_width)
break;
INT32 src_y = sy;
for (INT32 y = dy; y < dy + sh; y++, src_y++)
{
if (!in_bit_array(dpatch->pixels_opaque, position))
if (y < 0 || src_y < 0)
continue;
else if (y >= patch->height || src_y >= src_img_height)
break;
boolean opaque = false;
// Read pixel
void *input = readPixelFunc(pixels, informat, sx, src_y, src_img_width, src_img_height, 0);
// Determine opacity
if (input != NULL)
opaque = getAlphaFunc(input, 0) > 0;
size_t position = (x * patch->height) + y;
if (!opaque)
{
set_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
if (transparent_overwrite)
{
unset_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = dpatch->is_dirty = true;
}
}
else
{
if (!in_bit_array(dpatch->pixels_opaque, position))
{
set_bit_array(dpatch->pixels_opaque, position);
dpatch->update_columns = true;
}
writePixelFunc(&patch->pixels[position], input);
writePixelFunc(&patch->pixels[position], input);
dpatch->is_dirty = true;
dpatch->is_dirty = true;
}
}
}
}
}
boolean Patch_NeedsUpdate(patch_t *patch)
boolean Patch_NeedsUpdate(patch_t *patch, boolean needs_columns)
{
if (patch->type != PATCH_TYPE_DYNAMIC)
return false;
dynamicpatch_t *dpatch = (dynamicpatch_t *)patch;
return dpatch->is_dirty;
return dpatch->is_dirty || (needs_columns && dpatch->update_columns);
}
void Patch_DoDynamicUpdate(patch_t *patch)
void Patch_DoDynamicUpdate(patch_t *patch, boolean update_columns)
{
if (patch->type != PATCH_TYPE_DYNAMIC)
return;
@ -572,22 +779,25 @@ void Patch_DoDynamicUpdate(patch_t *patch)
if (Patch_CheckDirtyRect(dpatch))
{
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
}
if (update_columns && dpatch->update_columns && Patch_CheckDirtyColumns(dpatch))
{
for (INT32 x = dpatch->column_dirty[0]; x < dpatch->column_dirty[1]; x++)
Patch_RebuildColumn(patch, x, dpatch->pixels_opaque);
dpatch->update_columns = false;
Patch_ClearDirtyColumns(dpatch);
}
Patch_FreeMiscData(patch);
dpatch->is_dirty = false;
dpatch->update_columns = false;
Patch_ClearDirtyRect(dpatch);
}
@ -643,7 +853,7 @@ static void Patch_FreeData(patch_t *patch)
staticpatch_t *spatch = (staticpatch_t*)patch;
Z_Free(spatch->posts);
}
else if (patch->type == PATCH_TYPE_DYNAMIC)
else if (patch->type == PATCH_TYPE_DYNAMIC && patch->format == PATCH_FORMAT_PALETTE)
{
dynamicpatch_t *dpatch = (dynamicpatch_t*)patch;
for (INT32 x = 0; x < dpatch->patch.width; x++)
@ -684,7 +894,12 @@ void Patch_GenerateFlat(patch_t *patch, pictureflags_t flags)
{
UINT8 flip = (flags & (PICFLAGS_XFLIP | PICFLAGS_YFLIP));
if (patch->flats[flip] == NULL)
patch->flats[flip] = Picture_Convert(PICFMT_PATCH, patch, PICFMT_FLAT16, 0, NULL, 0, 0, 0, 0, flags);
{
if (patch->format == PATCH_FORMAT_RGBA)
patch->flats[flip] = Picture_Convert(PICFMT_PATCH32, patch->pixels, PICFMT_FLAT32, 0, NULL, 0, 0, 0, 0, flags);
else
patch->flats[flip] = Picture_Convert(PICFMT_PATCH, patch, PICFMT_FLAT16, 0, NULL, 0, 0, 0, 0, flags);
}
}
#ifdef HWRENDER

View file

@ -23,9 +23,15 @@ enum
PATCH_TYPE_DYNAMIC
};
enum
{
PATCH_FORMAT_PALETTE,
PATCH_FORMAT_RGBA
};
// Patch functions
patch_t *Patch_Create(INT16 width, INT16 height);
patch_t *Patch_CreateDynamic(INT16 width, INT16 height);
patch_t *Patch_CreateDynamic(INT16 width, INT16 height, UINT8 format);
void *Patch_GetPixel(patch_t *patch, INT32 x, INT32 y);
void Patch_SetPixel(patch_t *patch, void *pixel, pictureformat_t informat, INT32 x, INT32 y, boolean transparent_overwrite);
@ -35,8 +41,10 @@ void Patch_UpdatePixels(patch_t *patch,
INT32 sx, INT32 sy, INT32 sw, INT32 sh, INT32 dx, INT32 dy,
boolean transparent_overwrite);
boolean Patch_NeedsUpdate(patch_t *patch);
void Patch_DoDynamicUpdate(patch_t *patch);
unsigned Patch_GetBpp(patch_t *patch);
boolean Patch_NeedsUpdate(patch_t *patch, boolean needs_columns);
void Patch_DoDynamicUpdate(patch_t *patch, boolean update_columns);
void Patch_MarkDirtyRect(patch_t *dpatch, INT16 left, INT16 top, INT16 right, INT16 bottom);
void Patch_Clear(patch_t *patch);

View file

@ -160,7 +160,7 @@ static void RotatedPatch_CalculateDimensions(
void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip)
{
patch_t *rotated;
UINT16 *rawdst, *rawconv;
void *rawdst;
size_t size;
pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0;
@ -177,7 +177,6 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle
INT32 sx, sy;
INT32 dx, dy;
INT32 ox, oy;
INT32 minx, miny, maxx, maxy;
// Don't cache angle = 0
if (angle < 1 || angle >= ROTANGLES)
@ -205,89 +204,88 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle
newheight *= 2;
}
minx = newwidth;
miny = newheight;
maxx = 0;
maxy = 0;
// Draw the rotated sprite to a temporary buffer.
size = (newwidth * newheight);
if (!size)
size = (width * height);
rawdst = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL);
for (dy = 0; dy < newheight; dy++)
int format;
int patchformat;
if (patch->format == PATCH_FORMAT_RGBA)
{
for (dx = 0; dx < newwidth; dx++)
UINT32 *dest = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL);
patchformat = PICFMT_PATCH32;
for (dy = 0; dy < newheight; dy++)
{
x = (dx - (newwidth / 2)) * FRACUNIT;
y = (dy - (newheight / 2)) * FRACUNIT;
sx = FixedMul(x, ca) + FixedMul(y, sa) + xcenter;
sy = -FixedMul(x, sa) + FixedMul(y, ca) + ycenter;
sx >>= FRACBITS;
sy >>= FRACBITS;
if (sx >= 0 && sy >= 0 && sx < width && sy < height)
for (dx = 0; dx < newwidth; dx++)
{
void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip);
if (input != NULL)
x = (dx - (newwidth / 2)) * FRACUNIT;
y = (dy - (newheight / 2)) * FRACUNIT;
sx = FixedMul(x, ca) + FixedMul(y, sa) + xcenter;
sy = -FixedMul(x, sa) + FixedMul(y, ca) + ycenter;
sx >>= FRACBITS;
sy >>= FRACBITS;
if (sx >= 0 && sy >= 0 && sx < width && sy < height)
{
rawdst[(dy * newwidth) + dx] = (0xFF00 | (*(UINT8 *)input));
if (dx < minx)
minx = dx;
if (dy < miny)
miny = dy;
if (dx > maxx)
maxx = dx;
if (dy > maxy)
maxy = dy;
void *input = Picture_GetPatchPixel(patch, patchformat, sx, sy, bflip);
if (input != NULL)
{
dest[(dy * newwidth) + dx] = *(UINT32 *)input;
}
}
}
}
rawdst = dest;
format = PICFMT_FLAT32;
}
else
{
UINT16 *dest = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL);
patchformat = PICFMT_PATCH;
for (dy = 0; dy < newheight; dy++)
{
for (dx = 0; dx < newwidth; dx++)
{
x = (dx - (newwidth / 2)) * FRACUNIT;
y = (dy - (newheight / 2)) * FRACUNIT;
sx = FixedMul(x, ca) + FixedMul(y, sa) + xcenter;
sy = -FixedMul(x, sa) + FixedMul(y, ca) + ycenter;
sx >>= FRACBITS;
sy >>= FRACBITS;
if (sx >= 0 && sy >= 0 && sx < width && sy < height)
{
void *input = Picture_GetPatchPixel(patch, patchformat, sx, sy, bflip);
if (input != NULL)
{
dest[(dy * newwidth) + dx] = (0xFF00 | (*(UINT8 *)input));
}
}
}
}
rawdst = dest;
format = PICFMT_FLAT16;
}
ox = (newwidth / 2) + (leftoffset - xpivot);
oy = (newheight / 2) + (patch->topoffset - ypivot);
width = (maxx - minx);
height = (maxy - miny);
if ((unsigned)(width * height) > size)
{
UINT16 *src, *dest;
size = (width * height);
rawconv = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL);
src = &rawdst[(miny * newwidth) + minx];
dest = rawconv;
dy = height;
while (dy--)
{
M_Memcpy(dest, src, width * sizeof(UINT16));
dest += width;
src += newwidth;
}
ox -= minx;
oy -= miny;
Z_Free(rawdst);
}
else
{
rawconv = rawdst;
width = newwidth;
height = newheight;
}
// make patch
rotated = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawconv, PICFMT_PATCH, 0, NULL, width, height, 0, 0, 0);
rotated = (patch_t *)Picture_Convert(format, rawdst, patchformat, 0, NULL, newwidth, newheight, 0, 0, 0);
Z_ChangeTag(rotated, PU_PATCH_ROTATED);
Z_SetUser(rotated, (void **)(&rotsprite->patches[idx]));
Z_Free(rawconv);
Z_Free(rawdst);
rotated->leftoffset = ox;
rotated->topoffset = oy;

View file

@ -356,6 +356,7 @@ void *Picture_PatchConvert(
}
patch_t *out = Patch_Create(inwidth, inheight);
out->format = inbpp == PICDEPTH_32BPP ? PATCH_FORMAT_RGBA : PATCH_FORMAT_PALETTE;
out->leftoffset = inleftoffset;
out->topoffset = intopoffset;
@ -369,6 +370,8 @@ void *Picture_PatchConvert(
unsigned *column_posts = Z_Calloc(sizeof(unsigned) * inwidth, PU_STATIC, NULL);
size_t bpp = Patch_GetBpp(out);
// Write columns
for (INT32 x = 0; x < inwidth; x++)
{
@ -377,7 +380,11 @@ void *Picture_PatchConvert(
boolean was_opaque = false;
column_t *column = &out->columns[x];
column->pixels = imgptr;
if (out->format == PATCH_FORMAT_RGBA)
column->pixels = &out->pixels[out->height * x * bpp];
else
column->pixels = imgptr;
column->posts = NULL;
column->num_posts = 0;
@ -420,18 +427,30 @@ void *Picture_PatchConvert(
was_opaque = true;
// Write the pixel
UINT8 *last_ptr = imgptr;
imgptr = writePixelFunc(last_ptr, input);
if (out->format == PATCH_FORMAT_RGBA)
{
writePixelFunc(&column->pixels[y * bpp], input);
post_data_offset += bpp;
}
else
{
UINT8 *last_ptr = imgptr;
imgptr = writePixelFunc(last_ptr, input);
post_data_offset += imgptr - last_ptr;
}
post->length++;
post_data_offset += imgptr - last_ptr;
}
}
UINT8 *old_pixels = out->pixels;
size_t total_pixels = imgptr - out->pixels;
if (total_pixels != max_pixels)
out->pixels = Z_Realloc(out->pixels, total_pixels, PU_PATCH_DATA, NULL);
if (out->format != PATCH_FORMAT_RGBA)
{
size_t total_pixels = imgptr - out->pixels;
if (total_pixels != max_pixels)
out->pixels = Z_Realloc(out->pixels, total_pixels, PU_PATCH_DATA, NULL);
}
for (INT16 x = 0; x < inwidth; x++)
{

View file

@ -497,8 +497,141 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix
return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff));
}
static void V_DrawPatchRGBA(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap);
static void AdjustPositionByOffsets(patch_t *patch, fixed_t pscale, fixed_t vscale, INT32 scrn, fixed_t *x, fixed_t *y)
{
fixed_t offsetx = 0, offsety = 0;
// left offset
if (scrn & V_FLIP)
offsetx = FixedMul((patch->width - patch->leftoffset)<<FRACBITS, pscale) + 1;
else
offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale);
// top offset
offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
// Subtract the offsets from x/y positions
*x -= offsetx;
*y -= offsety;
}
static UINT8 AdjustPositionForScreen(INT32 *scrn, fixed_t *x, fixed_t *y, fixed_t *fdup, fixed_t *colfrac, fixed_t *vdup, fixed_t *rowfrac)
{
UINT8 perplayershuffle = 0;
INT32 flags = *scrn;
fixed_t adjusty = ((flags & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
*vdup >>= 1;
*rowfrac <<= 1;
*y >>= 1;
#ifndef QUADS
(void)x;
(void)fdup;
(void)colfrac;
#else
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((flags & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
*fdup >>= 1;
*colfrac <<= 1;
*x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
*scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
*x += adjustx;
*scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
*y += adjusty;
*scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
*x += adjustx;
*y += adjusty;
*scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 1;
*scrn &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 2;
*y += adjusty;
*scrn &= ~V_SNAPTOTOP;
}
}
return perplayershuffle;
}
static void AdjustPositionForVirtualRes(fixed_t dup, INT32 scrn, UINT8 perplayershuffle, fixed_t *x, fixed_t *y)
{
if (vid.width != BASEVIDWIDTH * dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (scrn & V_SNAPTORIGHT)
*x += (vid.width - (BASEVIDWIDTH * dup));
else if (!(scrn & V_SNAPTOLEFT))
*x += (vid.width - (BASEVIDWIDTH * dup)) / 2;
if (perplayershuffle & 4)
*x -= (vid.width - (BASEVIDWIDTH * dup)) / 4;
else if (perplayershuffle & 8)
*x += (vid.width - (BASEVIDWIDTH * dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * dup)
{
// same thing here
if (scrn & V_SNAPTOBOTTOM)
*y += (vid.height - (BASEVIDHEIGHT * dup));
else if (!(scrn & V_SNAPTOTOP))
*y += (vid.height - (BASEVIDHEIGHT * dup)) / 2;
if (perplayershuffle & 1)
*y -= (vid.height - (BASEVIDHEIGHT * dup)) / 4;
else if (perplayershuffle & 2)
*y += (vid.height - (BASEVIDHEIGHT * dup)) / 4;
}
}
// Draws a patch scaled to arbitrary size.
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_DrawPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap)
{
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
UINT32 alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT);
@ -514,10 +647,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
UINT8 perplayershuffle = 0;
if (Patch_NeedsUpdate(patch))
Patch_DoDynamicUpdate(patch);
if (patch->columns == NULL || rendermode == render_none)
if (rendermode == render_none)
return;
#ifdef HWRENDER
@ -528,6 +658,18 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
}
#endif
if (Patch_NeedsUpdate(patch, true))
Patch_DoDynamicUpdate(patch, true);
if (patch->columns == NULL)
return;
if (patch->format == PATCH_FORMAT_RGBA)
{
V_DrawPatchRGBA(x, y, pscale, vscale, scrn, patch, colormap);
return;
}
patchdrawfunc = standardpdraw;
v_translevel = NULL;
@ -577,92 +719,10 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, vdup);
{
fixed_t offsetx = 0, offsety = 0;
// left offset
if (scrn & V_FLIP)
offsetx = FixedMul((patch->width - patch->leftoffset)<<FRACBITS, pscale) + 1;
else
offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale);
// top offset
offsety = FixedMul(patch->topoffset<<FRACBITS, vscale);
// Subtract the offsets from x/y positions
x -= offsetx;
y -= offsety;
}
AdjustPositionByOffsets(patch, pscale, vscale, scrn, &x, &y);
if (splitscreen && (scrn & V_PERPLAYER))
{
fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
vdup >>= 1;
rowfrac <<= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
fdup >>= 1;
colfrac <<= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 1;
scrn &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 2;
y += adjusty;
scrn &= ~V_SNAPTOTOP;
}
}
}
perplayershuffle = AdjustPositionForScreen(&scrn, &x, &y, &fdup, &colfrac, &vdup, &rowfrac);
desttop = screens[scrn&V_PARAMMASK];
@ -698,31 +758,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
}
}
if (vid.width != BASEVIDWIDTH * dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (scrn & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * dup));
else if (!(scrn & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * dup)
{
// same thing here
if (scrn & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * dup));
else if (!(scrn & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * dup)) / 4;
}
AdjustPositionForVirtualRes(dup, scrn, perplayershuffle, &x, &y);
}
desttop += (y*vid.width) + x;
@ -779,6 +815,187 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
}
}
// Draws a patch scaled to arbitrary size.
static void V_DrawPatchRGBA(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap)
{
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
UINT32 alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT);
UINT32 blendmode = ((scrn & V_BLENDMASK) >> V_BLENDSHIFT);
fixed_t col, ofs, colfrac, rowfrac, fdup, vdup;
INT32 dup;
column_t *column;
UINT8 *desttop, *dest, *deststart, *destend;
const RGBA_t *source;
const UINT8 *deststop;
fixed_t pwidth; // patch width
fixed_t offx = 0; // x offset
UINT8 perplayershuffle = 0;
static colorlookup_t colorlookup;
if (Patch_NeedsUpdate(patch, true))
Patch_DoDynamicUpdate(patch, true);
if (patch->columns == NULL || rendermode == render_none)
return;
patchdrawfunc = standardpdraw;
v_translevel = NULL;
if (alphalevel || blendmode)
{
if (alphalevel == 10) // V_HUDTRANSHALF
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 11) // V_HUDTRANS
alphalevel = 10 - st_translucency;
else if (alphalevel == 12) // V_HUDTRANSDOUBLE
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
return; // invis
if (alphalevel || blendmode)
{
v_translevel = R_GetBlendTable(blendmode+1, alphalevel);
patchdrawfunc = translucentpdraw;
}
}
v_colormap = NULL;
if (colormap)
{
v_colormap = colormap;
patchdrawfunc = (v_translevel) ? transmappedpdraw : mappedpdraw;
}
dup = vid.dup;
if (scrn & V_SCALEPATCHMASK) switch (scrn & V_SCALEPATCHMASK)
{
case V_NOSCALEPATCH:
dup = 1;
break;
case V_SMALLSCALEPATCH:
dup = vid.smalldup;
break;
case V_MEDSCALEPATCH:
dup = vid.meddup;
break;
}
fdup = vdup = pscale * dup;
if (vscale != pscale)
vdup = vscale * dup;
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, vdup);
AdjustPositionByOffsets(patch, pscale, vscale, scrn, &x, &y);
if (splitscreen && (scrn & V_PERPLAYER))
perplayershuffle = AdjustPositionForScreen(&scrn, &x, &y, &fdup, &colfrac, &vdup, &rowfrac);
desttop = screens[scrn&V_PARAMMASK];
if (!desttop)
return;
InitColorLUT(&colorlookup, pMasterPalette, false);
deststop = desttop + vid.rowbytes * vid.height;
if (scrn & V_NOSCALESTART)
{
x >>= FRACBITS;
y >>= FRACBITS;
desttop += (y*vid.width) + x;
}
else
{
x *= dup;
y *= dup;
x >>= FRACBITS;
y >>= FRACBITS;
// Center it if necessary
if (!(scrn & V_SCALEPATCHMASK))
{
// if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
if (!v_translevel && x == 0 && patch->width == BASEVIDWIDTH && y == 0 && patch->height == BASEVIDHEIGHT)
{
column = &patch->columns[0];
if (column->num_posts && !column->posts[0].topdelta)
{
source = (RGBA_t*)column->pixels;
if (source->s.alpha)
{
UINT8 palidx = GetColorLUT(&colorlookup, source->s.red, source->s.green, source->s.blue);
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, palidx);
}
}
}
AdjustPositionForVirtualRes(dup, scrn, perplayershuffle, &x, &y);
}
desttop += (y*vid.width) + x;
}
if (pscale != FRACUNIT) // scale width properly
{
pwidth = patch->width<<FRACBITS;
pwidth = FixedMul(pwidth, pscale);
pwidth *= dup;
pwidth >>= FRACBITS;
}
else
pwidth = patch->width * dup;
deststart = desttop;
destend = desttop + pwidth;
for (col = 0; (col>>FRACBITS) < patch->width; col += colfrac, ++offx, desttop++)
{
if (scrn & V_FLIP) // offx is measured from right edge instead of left
{
if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
break;
if (x+pwidth-offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
continue;
}
else
{
if (x+offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
continue;
if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
break;
}
column = &patch->columns[col>>FRACBITS];
for (unsigned i = 0; i < column->num_posts; i++)
{
post_t *post = &column->posts[i];
source = (RGBA_t*)(column->pixels + post->data_offset);
dest = desttop;
if (scrn & V_FLIP)
dest = deststart + (destend - desttop);
dest += FixedInt(FixedMul(post->topdelta<<FRACBITS,vdup))*vid.width;
for (ofs = 0; dest < deststop && (size_t)(ofs>>FRACBITS) < post->length; ofs += rowfrac)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
{
RGBA_t texel = source[ofs>>FRACBITS];
UINT8 palidx = GetColorLUT(&colorlookup, texel.s.red, texel.s.green, texel.s.blue);
*dest = patchdrawfunc(dest, &palidx, 0);
}
dest += vid.width;
}
}
}
}
// Draws a patch cropped and scaled to arbitrary size.
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)
{
@ -794,9 +1011,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
UINT8 perplayershuffle = 0;
if (Patch_NeedsUpdate(patch))
Patch_DoDynamicUpdate(patch);
if (patch->columns == NULL || rendermode == render_none)
return;
@ -808,6 +1022,12 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
}
#endif
if (Patch_NeedsUpdate(patch, true))
Patch_DoDynamicUpdate(patch, true);
if (patch->columns == NULL || rendermode == render_none)
return;
patchdrawfunc = standardpdraw;
v_translevel = NULL;
@ -869,7 +1089,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
fdup >>= 1;
colfrac <<= 1;
x >>= 1;
@ -952,36 +1172,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
// Center it if necessary
if (!(scrn & V_SCALEPATCHMASK))
{
// if it's meant to cover the whole screen, black out the rest
// no the patch is cropped do not do this ever
if (vid.width != BASEVIDWIDTH * dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (scrn & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * dup));
else if (!(scrn & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * dup)
{
// same thing here
if (scrn & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * dup));
else if (!(scrn & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * dup)) / 4;
}
}
AdjustPositionForVirtualRes(dup, scrn, perplayershuffle, &x, &y);
desttop += (y*vid.width) + x;
}
@ -1057,8 +1248,8 @@ void V_DrawIntoPatch(patch_t *dest_patch, patch_t *src_patch, fixed_t x, fixed_t
dynamicpatch_t *dpatch = (dynamicpatch_t *)dest_patch;
if (Patch_NeedsUpdate(src_patch))
Patch_DoDynamicUpdate(src_patch);
if (Patch_NeedsUpdate(src_patch, true))
Patch_DoDynamicUpdate(src_patch, true);
if (src_patch->columns == NULL)
return;
@ -1110,23 +1301,7 @@ void V_DrawIntoPatch(patch_t *dest_patch, patch_t *src_patch, fixed_t x, fixed_t
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;
AdjustPositionByOffsets(src_patch, pscale, vscale, flags, &x, &y);
fixed_t pwidth = src_patch->width;
if (pscale != FRACUNIT)
@ -1404,31 +1579,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
h *= vid.dup;
// Center it if necessary
if (vid.width != BASEVIDWIDTH * vid.dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (c & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * vid.dup));
else if (!(c & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * vid.dup)
{
// same thing here
if (c & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * vid.dup));
else if (!(c & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
}
AdjustPositionForVirtualRes(vid.dup, c, perplayershuffle, &x, &y);
}
if (x >= vid.width || y >= vid.height)
@ -1608,31 +1759,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
h *= vid.dup;
// Center it if necessary
if (vid.width != BASEVIDWIDTH * vid.dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (c & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * vid.dup));
else if (!(c & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * vid.dup)
{
// same thing here
if (c & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * vid.dup));
else if (!(c & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
}
AdjustPositionForVirtualRes(vid.dup, c, perplayershuffle, &x, &y);
}
if (x >= vid.width || y >= vid.height)
@ -1790,31 +1917,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U
h *= vid.dup;
// Center it if necessary
if (vid.width != BASEVIDWIDTH * vid.dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (c & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * vid.dup));
else if (!(c & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * vid.dup)
{
// same thing here
if (c & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * vid.dup));
else if (!(c & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
}
AdjustPositionForVirtualRes(vid.dup, c, perplayershuffle, &x, &y);
}
if (x >= vid.width || y >= vid.height)

View file

@ -155,7 +155,6 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_PERPLAYER 0x80000000 // automatically adjust coordinates/scaling for splitscreen mode
// defines for old functions
#define V_DrawPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT, s|V_NOSCALESTART|V_NOSCALEPATCH, p, NULL)
#define V_DrawTranslucentMappedPatch(x,y,s,p,c) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT, s, p, c)
#define V_DrawSmallTranslucentMappedPatch(x,y,s,p,c) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/2, s, p, c)
#define V_DrawTinyTranslucentMappedPatch(x,y,s,p,c) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/4, s, p, c)
@ -170,8 +169,10 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_DrawTinyTranslucentPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/4, s, p, NULL)
#define V_DrawSciencePatch(x,y,s,p,sc) V_DrawFixedPatch(x,y,sc,s,p,NULL)
#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);
#define V_DrawStretchyFixedPatch(x,y,xs,ys,s,p,c) V_DrawPatch(x,y,xs,ys,s,p,c)
void V_DrawPatch(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);