[vulkan] Implement skin support

Finally, quakeworld gets its *ahem* fancy skins. I'm not happy with how
skin loading is handled, but the whole model and skin support needs a
redesign.

Closes #74.
This commit is contained in:
Bill Currie 2024-01-15 19:07:33 +09:00
parent fcd094ef04
commit ec9e2c12b8
6 changed files with 151 additions and 28 deletions

View file

@ -36,9 +36,25 @@
#include "QF/model.h"
#include "QF/Vulkan/qf_vid.h"
typedef struct vulkan_ctx_s vulkan_ctx_t;
typedef struct modelctx_s {
struct vulkan_ctx_s *ctx;
vulkan_ctx_t *ctx;
VkDeviceMemory texture_memory;
} modelctx_t;
typedef struct skin_s skin_t;
typedef struct mod_alias_ctx_s mod_alias_ctx_t;
typedef struct maliasskindesc_s maliasskindesc_t;
typedef struct qfv_alias_skin_s qfv_alias_skin_t;
qfv_alias_skin_t *
Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix,
int skinsize, int snum, int gnum, bool group,
maliasskindesc_t *skindesc, vulkan_ctx_t *ctx);
void Vulkan_Skin_Clear (qfv_alias_skin_t *skin, vulkan_ctx_t *ctx);
void Vulkan_Skin_SetupSkin (skin_t *skin, struct vulkan_ctx_s *ctx);
void Vulkan_Skin_Destroy (skin_t *skin, struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_model_h

View file

@ -316,7 +316,7 @@ typedef struct {
char name[16];
} maliasframedesc_t;
typedef struct {
typedef struct maliasskindesc_s {
aliasskintype_t type;
int skin;
int texnum;

View file

@ -46,6 +46,7 @@
#include "QF/modelgen.h"
#include "QF/vid.h"
#include "QF/Vulkan/qf_alias.h"
#include "QF/Vulkan/qf_model.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/barrier.h"
#include "QF/Vulkan/buffer.h"
@ -64,17 +65,10 @@ static vec3_t vertex_normals[NUMVERTEXNORMALS] = {
#include "anorms.h"
};
static void
skin_clear (int skin_offset, aliashdr_t *hdr, vulkan_ctx_t *ctx)
static qfv_alias_skin_t *
find_skin (int skin_offset, aliashdr_t *hdr)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_alias_skin_t *skin = (qfv_alias_skin_t *) ((byte *) hdr + skin_offset);
Vulkan_AliasRemoveSkin (ctx, skin);
dfunc->vkDestroyImageView (device->dev, skin->view, 0);
dfunc->vkDestroyImage (device->dev, skin->image, 0);
dfunc->vkFreeMemory (device->dev, skin->memory, 0);
return (qfv_alias_skin_t *) ((byte *) hdr + skin_offset);
}
static void
@ -101,35 +95,37 @@ vulkan_alias_clear (model_t *m, void *data)
__auto_type group = (maliasskingroup_t *)
((byte *) hdr + skins[i].skin);
for (int j = 0; j < group->numskins; j++) {
skin_clear (group->skindescs[j].skin, hdr, ctx);
auto skin = find_skin (group->skindescs[j].skin, hdr);
Vulkan_Skin_Clear (skin, ctx);
}
} else {
skin_clear (skins[i].skin, hdr, ctx);
auto skin = find_skin (skins[i].skin, hdr);
Vulkan_Skin_Clear (skin, ctx);
}
}
}
#define SKIN_LAYERS 3
static void *
qfv_alias_skin_t *
Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize,
int snum, int gnum, bool group,
maliasskindesc_t *skindesc, vulkan_ctx_t *ctx)
{
qfvPushDebug (ctx, va (ctx->va_ctx, "alias.load_skin: %s", alias_ctx->mod->name));
const char *mod_name = alias_ctx->mod->name;
qfvPushDebug (ctx, va (ctx->va_ctx, "alias.load_skin: %s", mod_name));
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
aliashdr_t *header = alias_ctx->header;
int w = header->mdl.skinwidth;
int h = header->mdl.skinheight;
qfv_alias_skin_t *skin;
byte *tskin;
int w, h;
skin = Hunk_Alloc (0, sizeof (qfv_alias_skin_t));
QuatSet (TOP_RANGE + 7, BOTTOM_RANGE + 7, 0, 0, skin->colors);
skindesc->skin = (byte *) skin - (byte *) header;
//FIXME move all skins into arrays(?)
w = header->mdl.skinwidth;
h = header->mdl.skinheight;
tskin = malloc (2 * skinsize);
memcpy (tskin, skinpix, skinsize);
Mod_FloodFillSkin (tskin, w, h);
@ -144,13 +140,13 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize,
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skin->image,
va (ctx->va_ctx, "image:%s:%d:%d",
alias_ctx->mod->name, snum, gnum));
mod_name, snum, gnum));
skin->memory = QFV_AllocImageMemory (device, skin->image,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
0, 0);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, skin->memory,
va (ctx->va_ctx, "memory:%s:%d:%d",
alias_ctx->mod->name, snum, gnum));
mod_name, snum, gnum));
QFV_BindImageMemory (device, skin->image, skin->memory, 0);
skin->view = QFV_CreateImageView (device, skin->image,
VK_IMAGE_VIEW_TYPE_2D_ARRAY,
@ -158,7 +154,7 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize,
VK_IMAGE_ASPECT_COLOR_BIT);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, skin->view,
va (ctx->va_ctx, "iview:%s:%d:%d",
alias_ctx->mod->name, snum, gnum));
mod_name, snum, gnum));
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, "alias stage",
SKIN_LAYERS * skinsize * 4,
@ -220,7 +216,7 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize,
Vulkan_AliasAddSkin (ctx, skin);
qfvPopDebug (ctx);
return skinpix + skinsize;
return skin;
}
void

View file

@ -0,0 +1,97 @@
/*
vulkan_skin.c
Vulkan Skin support
Copyright (C) 2024 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2024/1/15
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, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include "string.h"
#endif
#ifdef HAVE_STRINGS_H
# include "strings.h"
#endif
#include <stdlib.h>
#include "QF/image.h"
#include "QF/model.h"
#include "QF/skin.h"
#include "QF/sys.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/qf_alias.h"
#include "QF/Vulkan/qf_model.h"
#include "mod_internal.h"
#include "vid_vulkan.h"
void
Vulkan_Skin_Clear (qfv_alias_skin_t *skin, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
Vulkan_AliasRemoveSkin (ctx, skin);
dfunc->vkDestroyImageView (device->dev, skin->view, 0);
dfunc->vkDestroyImage (device->dev, skin->image, 0);
dfunc->vkFreeMemory (device->dev, skin->memory, 0);
}
void
Vulkan_Skin_SetupSkin (skin_t *skin, struct vulkan_ctx_s *ctx)
{
tex_t *tex = skin->tex;
// FIXME this is gross, but the vulkan skin (and even model) handling
// needs a complete overhaul.
aliashdr_t dummy_header = {
.mdl.skinwidth = tex->width,
.mdl.skinheight = tex->height,
};
model_t dummy_model = { };
mod_alias_ctx_t alias_ctx = {
.header = &dummy_header,
.mod = &dummy_model,
};
maliasskindesc_t skindesc = {};
int skinsize = tex->width * tex->height;
size_t hunk_mark = Hunk_LowMark (0);
auto vkskin = Vulkan_Mod_LoadSkin (&alias_ctx, tex->data, skinsize,
0, 0, false, &skindesc, ctx);
skin->tex = malloc (sizeof (*vkskin));
*(qfv_alias_skin_t *) skin->tex = *vkskin;
Hunk_FreeToLowMark (0, hunk_mark);
}
void
Vulkan_Skin_Destroy (skin_t *skin, struct vulkan_ctx_s *ctx)
{
auto alias_skin = (qfv_alias_skin_t *) skin->tex;
Vulkan_Skin_Clear (alias_skin, ctx);
}

View file

@ -49,6 +49,7 @@
#include "QF/Vulkan/qf_lighting.h"
#include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_model.h"
#include "QF/Vulkan/qf_output.h"
#include "QF/Vulkan/qf_palette.h"
#include "QF/Vulkan/qf_particles.h"
@ -454,6 +455,13 @@ vulkan_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx)
static void
vulkan_Skin_SetupSkin (struct skin_s *skin)
{
Vulkan_Skin_SetupSkin (skin, vulkan_ctx);
}
static void
vulkan_Skin_Destroy (struct skin_s *skin)
{
Vulkan_Skin_Destroy (skin, vulkan_ctx);
}
static void
@ -515,6 +523,7 @@ static vid_model_funcs_t model_funcs = {
.skin_set = Skin_Set,
.skin_setupskin = vulkan_Skin_SetupSkin,
.skin_destroy = vulkan_Skin_Destroy,
};
static void

View file

@ -50,6 +50,7 @@
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/render.h"
#include "mod_internal.h"
#include "r_internal.h"
#include "vid_vulkan.h"
@ -177,7 +178,6 @@ alias_draw_ent (qfv_taskctx_t *taskctx, entity_t ent, bool pass,
{
auto model = renderer->model;
aliashdr_t *hdr;
qfv_alias_skin_t *skin;
uint16_t *matrix_base = taskctx->data;
if (!(hdr = model->aliashdr)) {
@ -189,9 +189,14 @@ alias_draw_ent (qfv_taskctx_t *taskctx, entity_t ent, bool pass,
transform_t transform = Entity_Transform (ent);
if (0/*XXX ent->skin && ent->skin->tex*/) {
//skin = ent->skin->tex;
} else {
qfv_alias_skin_t *skin = nullptr;
if (renderer->skin) {
skin_t *tskin = Skin_Get (renderer->skin);
if (tskin) {
skin = (qfv_alias_skin_t *) tskin->tex;
}
}
if (!skin) {
maliasskindesc_t *skindesc;
skindesc = R_AliasGetSkindesc (animation, renderer->skinnum, hdr);
skin = (qfv_alias_skin_t *) ((byte *) hdr + skindesc->skin);