mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-11 20:03:11 +00:00
[vulkan] Regenerate mips for transparent textures
BSP textures have pre-generated mips, including the transparent textures, but mips don't play nicely with the transparency color (255): it gets blended to other colors (at least in ad tears). Regenerating the mips from the rgba texture (using transparent black) produces nice results. Also, needed to discard on 0 alpha to avoid weird interactions with fog (I didn't know ad tears had fog: I guess I had last loaded it before implementing fog).
This commit is contained in:
parent
d46620fcf4
commit
e7401c5ff4
2 changed files with 57 additions and 30 deletions
|
@ -99,35 +99,42 @@ mipsize (size_t size)
|
|||
}
|
||||
|
||||
static void
|
||||
transfer_mips (byte *dst, const void *_src, const texture_t *tx, byte *palette,
|
||||
transfer_mip_level (byte *dst, const void *src, const texture_t *tx, int level,
|
||||
byte *palette, vprocess_t process)
|
||||
{
|
||||
unsigned width = tx->width >> level;
|
||||
unsigned height = tx->height >> level;
|
||||
unsigned count = width * height;
|
||||
|
||||
// mip offsets are relative to the texture pointer rather than the
|
||||
// end of the texture struct
|
||||
unsigned offset = tx->offsets[level] - sizeof (texture_t);
|
||||
// use the upper block of the destination as a temporary buffer for
|
||||
// the processed pixels. Vulkan_ExpandPalette works in a linearly
|
||||
// increasing manner thus the processed pixels will be overwritten
|
||||
// only after they have been read
|
||||
byte *tmp = dst + count * 3;
|
||||
process (tmp, src + offset, count);
|
||||
Vulkan_ExpandPalette (dst, tmp, palette, 2, count);
|
||||
}
|
||||
|
||||
static void
|
||||
transfer_mips (byte *dst, const void *src, const texture_t *tx, byte *palette,
|
||||
vprocess_t process)
|
||||
{
|
||||
const byte *src = _src;
|
||||
unsigned width = tx->width;
|
||||
unsigned height = tx->height;
|
||||
unsigned count, offset;
|
||||
|
||||
for (int i = 0; i < MIPLEVELS; i++) {
|
||||
// mip offsets are relative to the texture pointer rather than the
|
||||
// end of the texture struct
|
||||
offset = tx->offsets[i] - sizeof (texture_t);
|
||||
count = width * height;
|
||||
// use the upper block of the destination as a temporary buffer for
|
||||
// the processed pixels. Vulkan_ExpandPalette works in a linearly
|
||||
// increasing manner thus the processed pixels will be overwritten
|
||||
// only after they have been read
|
||||
byte *tmp = dst + count * 3;
|
||||
process (tmp, src + offset, count);
|
||||
Vulkan_ExpandPalette (dst, tmp, palette, 2, count);
|
||||
transfer_mip_level (dst, src, tx, i, palette, process);
|
||||
|
||||
unsigned width = tx->width >> i;
|
||||
unsigned height = tx->height >> i;
|
||||
unsigned count = width * height;
|
||||
dst += count * 4;
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
copy_mips (qfv_packet_t *packet, texture_t *tx, size_t offset, VkImage image,
|
||||
int layer, qfv_devfuncs_t *dfunc)
|
||||
int layer, int miplevels, qfv_devfuncs_t *dfunc)
|
||||
{
|
||||
// base copy
|
||||
VkBufferImageCopy copy = {
|
||||
|
@ -153,7 +160,7 @@ copy_mips (qfv_packet_t *packet, texture_t *tx, size_t offset, VkImage image,
|
|||
__auto_type copies = QFV_AllocBufferImageCopy (copy_count, alloca);
|
||||
copies->size = 0;
|
||||
|
||||
for (int i = 0; i < MIPLEVELS; i++) {
|
||||
for (int i = 0; i < miplevels; i++) {
|
||||
__auto_type c = &copies->a[copies->size++];
|
||||
*c = copy;
|
||||
if (is_sky) {
|
||||
|
@ -179,8 +186,10 @@ copy_mips (qfv_packet_t *packet, texture_t *tx, size_t offset, VkImage image,
|
|||
|
||||
static void
|
||||
transfer_texture (texture_t *tx, VkImage image, qfv_packet_t *packet,
|
||||
byte *palette, qfv_devfuncs_t *dfunc)
|
||||
byte *palette, qfv_device_t *device)
|
||||
{
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
|
||||
byte *base = packet->stage->data;
|
||||
|
||||
size_t layer_size = mipsize (tx->width * tx->height * 4);
|
||||
|
@ -196,13 +205,18 @@ transfer_texture (texture_t *tx, VkImage image, qfv_packet_t *packet,
|
|||
|
||||
if (strncmp (tx->name, "sky", 3) == 0) {
|
||||
transfer_mips (dst, tx + 1, tx, palette, (vprocess_t) memcpy);
|
||||
copy_mips (packet, tx, dst - base, image, 0, dfunc);
|
||||
copy_mips (packet, tx, dst - base, image, 0, MIPLEVELS, dfunc);
|
||||
} else if (tx->name[0] == '{') {
|
||||
transfer_mip_level (dst, tx + 1, tx, 0, palette, (vprocess_t) memcpy);
|
||||
copy_mips (packet, tx, dst - base, image, 0, 1, dfunc);
|
||||
QFV_GenerateMipMaps (device, packet->cmd, image, MIPLEVELS,
|
||||
tx->width, tx->height, 1);
|
||||
} else {
|
||||
transfer_mips (dst, tx + 1, tx, palette, Mod_ClearFullbright);
|
||||
copy_mips (packet, tx, dst - base, image, 0, dfunc);
|
||||
copy_mips (packet, tx, dst - base, image, 0, MIPLEVELS, dfunc);
|
||||
byte *glow = QFV_PacketExtend (packet, layer_size);
|
||||
transfer_mips (glow, tx + 1, tx, palette, Mod_CalcFullbright);
|
||||
copy_mips (packet, tx, glow - base, image, 1, dfunc);
|
||||
copy_mips (packet, tx, glow - base, image, 1, MIPLEVELS, dfunc);
|
||||
}
|
||||
|
||||
ib = imageBarriers[qfv_LT_TransferDst_to_ShaderReadOnly];
|
||||
|
@ -224,12 +238,16 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx)
|
|||
mod_brush_t *brush = &mod->brush;
|
||||
VkImage image = 0;
|
||||
byte sky_palette[256 * 4];
|
||||
byte trans_palette[256 * 4];
|
||||
|
||||
memcpy (sky_palette, vid.palette32, sizeof (sky_palette));
|
||||
memcpy (trans_palette, vid.palette32, sizeof (trans_palette));
|
||||
// sky's black is transparent
|
||||
// this hits both layers, but so long as the screen is cleared
|
||||
// to black, no one should notice :)
|
||||
sky_palette[3] = 0;
|
||||
// transparent textures want transparent black
|
||||
memset (trans_palette + 255*4, 0, 4);
|
||||
|
||||
size_t memsize = 0;
|
||||
for (unsigned i = 0; i < brush->numtextures; i++) {
|
||||
|
@ -268,19 +286,22 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx)
|
|||
offset += QFV_GetImageSize (device, tex->image);
|
||||
|
||||
VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
tex->view = QFV_CreateImageView (device, tex->image,
|
||||
type, VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
tex->view = QFV_CreateImageView (device, tex->image, type,
|
||||
VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW,
|
||||
tex->view,
|
||||
va (ctx->va_ctx, "iview:%s:%s:tex",
|
||||
mod->name, tx->name));
|
||||
|
||||
byte *palette = vid.palette32;
|
||||
if (strncmp (tx->name, "sky", 3) == 0) {
|
||||
if (tx->name[0] == '{') {
|
||||
printf ("%s\n", tx->name);
|
||||
palette = trans_palette;
|
||||
} else if (strncmp (tx->name, "sky", 3) == 0) {
|
||||
palette = sky_palette;
|
||||
}
|
||||
transfer_texture (tx, tex->image, packet, palette, dfunc);
|
||||
transfer_texture (tx, tex->image, packet, palette, device);
|
||||
}
|
||||
QFV_PacketSubmit (packet);
|
||||
QFV_DestroyStagingBuffer (stage);
|
||||
|
@ -317,6 +338,9 @@ Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, vulkan_ctx_t *ctx)
|
|||
if (tx->width == 2 * tx->height) {
|
||||
extent.width /= 2;
|
||||
}
|
||||
} else if (tx->name[0] == '{') {
|
||||
// trasparent textures don't have glow color
|
||||
layers = 1;
|
||||
}
|
||||
|
||||
tex->tex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
|
||||
|
|
|
@ -43,6 +43,9 @@ main (void)
|
|||
vec4 c = texture (Texture, vec3(st, 0));
|
||||
vec4 e = texture (Texture, vec3(st, 1));
|
||||
float a = c.a * e.a * alpha;
|
||||
if (a == 0) {
|
||||
discard;
|
||||
}
|
||||
c += e;
|
||||
c.a = a;
|
||||
c = FogBlend (c * color, fog);
|
||||
|
|
Loading…
Reference in a new issue