mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-24 10:31:35 +00:00
[vulkan] Use resource for allocating alias models
So far only the mesh data, so it doesn't make any difference to allocations, but it's the first step to reducing memory object allocation.
This commit is contained in:
parent
4ed1ef3353
commit
2e9e247ca4
2 changed files with 186 additions and 191 deletions
|
@ -56,7 +56,7 @@ typedef struct qfv_alias_mesh_s {
|
|||
VkBuffer vertex_buffer;
|
||||
VkBuffer uv_buffer;
|
||||
VkBuffer index_buffer;
|
||||
VkDeviceMemory memory;
|
||||
struct qfv_resource_s *resources;
|
||||
} qfv_alias_mesh_t;
|
||||
|
||||
typedef struct qfv_alias_skin_s {
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "QF/Vulkan/debug.h"
|
||||
#include "QF/Vulkan/image.h"
|
||||
#include "QF/Vulkan/instance.h"
|
||||
#include "QF/Vulkan/resource.h"
|
||||
#include "QF/Vulkan/staging.h"
|
||||
|
||||
#include "mod_internal.h"
|
||||
|
@ -81,7 +82,6 @@ vulkan_alias_clear (model_t *m, void *data)
|
|||
{
|
||||
vulkan_ctx_t *ctx = data;
|
||||
qfv_device_t *device = ctx->device;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
aliashdr_t *hdr;
|
||||
qfv_alias_mesh_t *mesh;
|
||||
|
||||
|
@ -92,10 +92,7 @@ vulkan_alias_clear (model_t *m, void *data)
|
|||
hdr = Cache_Get (&m->cache);
|
||||
}
|
||||
mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands);
|
||||
dfunc->vkDestroyBuffer (device->dev, mesh->vertex_buffer, 0);
|
||||
dfunc->vkDestroyBuffer (device->dev, mesh->uv_buffer, 0);
|
||||
dfunc->vkDestroyBuffer (device->dev, mesh->index_buffer, 0);
|
||||
dfunc->vkFreeMemory (device->dev, mesh->memory, 0);
|
||||
QFV_DestroyResource (device, mesh->resources);
|
||||
|
||||
__auto_type skins = (maliasskindesc_t *) ((byte *) hdr + hdr->skindesc);
|
||||
for (int i = 0; i < hdr->mdl.numskins; i++) {
|
||||
|
@ -239,67 +236,14 @@ Vulkan_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx)
|
||||
static int
|
||||
separate_verts (int *indexmap, int numverts, int numtris,
|
||||
const mod_alias_ctx_t *alias_ctx)
|
||||
{
|
||||
alias_ctx->mod->clear = vulkan_alias_clear;
|
||||
alias_ctx->mod->data = ctx;
|
||||
}
|
||||
|
||||
void
|
||||
Vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_buffer_size (qfv_device_t *device, VkBuffer buffer)
|
||||
{
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
size_t size;
|
||||
size_t align;
|
||||
|
||||
VkMemoryRequirements requirements;
|
||||
dfunc->vkGetBufferMemoryRequirements (device->dev, buffer, &requirements);
|
||||
size = requirements.size;
|
||||
align = requirements.alignment - 1;
|
||||
size = (size + align) & ~(align);
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m,
|
||||
int _s, int extra, vulkan_ctx_t *ctx)
|
||||
{
|
||||
aliashdr_t *header = alias_ctx->header;
|
||||
qfv_device_t *device = ctx->device;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
aliasvrt_t *verts;
|
||||
aliasuv_t *uv;
|
||||
trivertx_t *pv;
|
||||
int *indexmap;
|
||||
uint32_t *indices;
|
||||
int numverts;
|
||||
int numtris;
|
||||
int i, j;
|
||||
int pose;
|
||||
vec3_t pos;
|
||||
|
||||
if (header->mdl.ident == HEADER_MDL16)
|
||||
VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale);
|
||||
|
||||
numverts = header->mdl.numverts;
|
||||
numtris = header->mdl.numtris;
|
||||
|
||||
// initialize indexmap to -1 (unduplicated). any other value indicates
|
||||
// both that the vertex has been duplicated and the index of the
|
||||
// duplicate vertex.
|
||||
indexmap = malloc (numverts * sizeof (int));
|
||||
memset (indexmap, -1, numverts * sizeof (int));
|
||||
|
||||
// check for onseam verts, and duplicate any that are associated with
|
||||
// back-facing triangles
|
||||
for (i = 0; i < numtris; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
for (int i = 0; i < numtris; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int vind = alias_ctx->triangles.a[i].vertindex[j];
|
||||
if (alias_ctx->stverts.a[vind].onseam
|
||||
&& !alias_ctx->triangles.a[i].facesfront) {
|
||||
|
@ -311,92 +255,27 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m,
|
|||
}
|
||||
}
|
||||
}
|
||||
return numverts;
|
||||
}
|
||||
|
||||
// we now know exactly how many vertices we need, so built the vertex
|
||||
// and index data arrays
|
||||
// The layout is:
|
||||
// vbuf:{vertex, normal} * (numposes * numverts)
|
||||
// uvbuf:{uv} * (numverts)
|
||||
// ibuf:{index} * (numtris * 3)
|
||||
// numverts includes the duplicated seam vertices.
|
||||
// The vertex buffer will be bound with various offsets based on the
|
||||
// current and previous pose, uvbuff "statically" bound as uvs are not
|
||||
// animated by pose, and the same for ibuf: indices will never change for
|
||||
// the mesh
|
||||
size_t vert_count = numverts * header->numposes;
|
||||
size_t vert_size = vert_count * sizeof (aliasvrt_t);
|
||||
size_t uv_size = numverts * sizeof (aliasuv_t);
|
||||
size_t ind_size = 3 * numtris * sizeof (uint32_t);
|
||||
|
||||
VkBuffer vbuff = QFV_CreateBuffer (device, vert_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
VkBuffer uvbuff = QFV_CreateBuffer (device, uv_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
VkBuffer ibuff = QFV_CreateBuffer (device, ind_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, vbuff,
|
||||
va (ctx->va_ctx, "buffer:alias:vertex:%s",
|
||||
alias_ctx->mod->name));
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, uvbuff,
|
||||
va (ctx->va_ctx, "buffer:alias:uv:%s",
|
||||
alias_ctx->mod->name));
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, ibuff,
|
||||
va (ctx->va_ctx, "buffer:alias:index:%s",
|
||||
alias_ctx->mod->name));
|
||||
size_t voffs = 0;
|
||||
size_t uvoffs = voffs + get_buffer_size (device, vbuff);
|
||||
size_t ioffs = uvoffs + get_buffer_size (device, uvbuff);
|
||||
size_t buff_size = ioffs + get_buffer_size (device, ibuff);
|
||||
VkDeviceMemory mem;
|
||||
mem = QFV_AllocBufferMemory (device, vbuff,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
buff_size, 0);
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, mem,
|
||||
va (ctx->va_ctx, "memory:alias:vuvi:%s",
|
||||
alias_ctx->mod->name));
|
||||
QFV_BindBufferMemory (device, vbuff, mem, voffs);
|
||||
QFV_BindBufferMemory (device, uvbuff, mem, uvoffs);
|
||||
QFV_BindBufferMemory (device, ibuff, mem, ioffs);
|
||||
|
||||
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device,
|
||||
va (ctx->va_ctx,
|
||||
"alias:%s",
|
||||
alias_ctx->mod->name),
|
||||
buff_size, ctx->cmdpool);
|
||||
qfv_packet_t *packet = QFV_PacketAcquire (stage);
|
||||
verts = QFV_PacketExtend (packet, vert_size);
|
||||
uv = QFV_PacketExtend (packet, uv_size);
|
||||
indices = QFV_PacketExtend (packet, ind_size);
|
||||
|
||||
// populate the uvs, duplicating and shifting any that are on the seam
|
||||
// and associated with back-facing triangles (marked by non-negative
|
||||
// indexmap entry).
|
||||
// the s coordinate is shifted right by half the skin width.
|
||||
for (i = 0; i < header->mdl.numverts; i++) {
|
||||
int vind = indexmap[i];
|
||||
uv[i].u = (float) alias_ctx->stverts.a[i].s / header->mdl.skinwidth;
|
||||
uv[i].v = (float) alias_ctx->stverts.a[i].t / header->mdl.skinheight;
|
||||
if (vind != -1) {
|
||||
uv[vind] = uv[i];
|
||||
uv[vind].u += 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
// poputlate the vertex position and normal data, duplicating for
|
||||
static void
|
||||
build_verts (aliasvrt_t *verts, int numposes, int numverts, const mdl_t *mdl,
|
||||
const int *indexmap, const mod_alias_ctx_t *alias_ctx)
|
||||
{
|
||||
int i, pose;
|
||||
// populate the vertex position and normal data, duplicating for
|
||||
// back-facing on-seam verts (indicated by non-negative indexmap entry)
|
||||
for (i = 0, pose = 0; i < header->numposes; i++, pose += numverts) {
|
||||
for (j = 0; j < header->mdl.numverts; j++) {
|
||||
pv = &alias_ctx->poseverts.a[i][j];
|
||||
if (extra) {
|
||||
VectorMultAdd (pv[header->mdl.numverts].v, 256, pv->v, pos);
|
||||
for (i = 0, pose = 0; i < numposes; i++, pose += numverts) {
|
||||
for (int j = 0; j < mdl->numverts; j++) {
|
||||
auto pv = &alias_ctx->poseverts.a[i][j];
|
||||
vec3_t pos;
|
||||
if (mdl->ident == HEADER_MDL16) {
|
||||
VectorMultAdd (pv[mdl->numverts].v, 256, pv->v, pos);
|
||||
} else {
|
||||
VectorCopy (pv->v, pos);
|
||||
}
|
||||
VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale,
|
||||
pos, verts[pose + j].vertex);
|
||||
VectorCompMultAdd (mdl->scale_origin, mdl->scale, pos,
|
||||
verts[pose + j].vertex);
|
||||
verts[pose + j].vertex[3] = 1;
|
||||
VectorCopy (vertex_normals[pv->lightnormalindex],
|
||||
verts[pose + j].normal);
|
||||
|
@ -407,10 +286,35 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
build_uvs (aliasuv_t *uv, const mdl_t *mdl, const int *indexmap,
|
||||
const mod_alias_ctx_t *alias_ctx)
|
||||
{
|
||||
// populate the uvs, duplicating and shifting any that are on the seam
|
||||
// and associated with back-facing triangles (marked by non-negative
|
||||
// indexmap entry).
|
||||
// the s coordinate is shifted right by half the skin width.
|
||||
for (int i = 0; i < mdl->numverts; i++) {
|
||||
int vind = indexmap[i];
|
||||
uv[i].u = (float) alias_ctx->stverts.a[i].s / mdl->skinwidth;
|
||||
uv[i].v = (float) alias_ctx->stverts.a[i].t / mdl->skinheight;
|
||||
if (vind != -1) {
|
||||
uv[vind] = uv[i];
|
||||
uv[vind].u += 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
build_inds (uint32_t *indices, int numtris, const int *indexmap,
|
||||
const mod_alias_ctx_t *alias_ctx)
|
||||
{
|
||||
|
||||
// now build the indices for DrawElements
|
||||
for (i = 0; i < numtris; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
for (int i = 0; i < numtris; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int vind = alias_ctx->triangles.a[i].vertindex[j];
|
||||
// can't use indexmap to do the test because it indicates only
|
||||
// that the vertex has been duplicated, not whether or not
|
||||
|
@ -422,57 +326,148 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m,
|
|||
indices[3 * i + j] = vind;
|
||||
}
|
||||
}
|
||||
// finished with indexmap
|
||||
free (indexmap);
|
||||
}
|
||||
|
||||
header->poseverts = numverts;
|
||||
void
|
||||
Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx)
|
||||
{
|
||||
auto device = ctx->device;
|
||||
|
||||
qfv_bufferbarrier_t bb = bufferBarriers[qfv_BB_Unknown_to_TransferWrite];
|
||||
VkBufferMemoryBarrier wr_barriers[] = {
|
||||
bb.barrier, bb.barrier, bb.barrier,
|
||||
alias_ctx->mod->clear = vulkan_alias_clear;
|
||||
alias_ctx->mod->data = ctx;
|
||||
|
||||
auto hdr = alias_ctx->header;
|
||||
|
||||
int numverts = hdr->mdl.numverts;
|
||||
int numtris = hdr->mdl.numtris;
|
||||
|
||||
int indexmap[numverts];
|
||||
// initialize indexmap to -1 (unduplicated). any other value indicates
|
||||
// both that the vertex has been duplicated and the index of the
|
||||
// duplicate vertex.
|
||||
memset (indexmap, -1, sizeof (indexmap));
|
||||
|
||||
numverts = separate_verts (indexmap, numverts, numtris, alias_ctx);
|
||||
hdr->poseverts = numverts;
|
||||
// we now know exactly how many vertices we need, so build the vertex
|
||||
// and index data arrays
|
||||
// The layout is:
|
||||
// vbuf:{vertex, normal} * (numposes * numverts)
|
||||
// uvbuf:{uv} * (numverts)
|
||||
// ibuf:{index} * (numtris * 3)
|
||||
// numverts includes the duplicated seam vertices.
|
||||
// The vertex buffer will be bound with various offsets based on the
|
||||
// current and previous pose, uvbuff "statically" bound as uvs are not
|
||||
// animated by pose, and the same for ibuf: indices will never change for
|
||||
// the mesh
|
||||
size_t vert_count = numverts * hdr->numposes;
|
||||
size_t vert_size = vert_count * sizeof (aliasvrt_t);
|
||||
size_t uv_size = numverts * sizeof (aliasuv_t);
|
||||
size_t ind_size = 3 * numtris * sizeof (uint32_t);
|
||||
auto mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands);
|
||||
mesh->resources = malloc (sizeof (qfv_resource_t)
|
||||
+ sizeof (qfv_resobj_t)
|
||||
+ sizeof (qfv_resobj_t)
|
||||
+ sizeof (qfv_resobj_t));
|
||||
mesh->resources[0] = (qfv_resource_t) {
|
||||
.name = va (ctx->va_ctx, "alias:%s", alias_ctx->mod->name),
|
||||
.va_ctx = ctx->va_ctx,
|
||||
.memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
.num_objects = 3,
|
||||
.objects = (qfv_resobj_t *) &mesh->resources[1],
|
||||
};
|
||||
wr_barriers[0].buffer = vbuff;
|
||||
wr_barriers[0].size = vert_size;
|
||||
wr_barriers[1].buffer = uvbuff;
|
||||
wr_barriers[1].size = uv_size;
|
||||
wr_barriers[2].buffer = ibuff;
|
||||
wr_barriers[2].size = ind_size;
|
||||
dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages,
|
||||
0, 0, 0, 3, wr_barriers, 0, 0);
|
||||
VkBufferCopy copy_region[] = {
|
||||
{ packet->offset, 0, vert_size },
|
||||
{ packet->offset + vert_size, 0, uv_size },
|
||||
{ packet->offset + vert_size + uv_size, 0, ind_size },
|
||||
auto vert_obj = mesh->resources->objects;
|
||||
auto uv_obj = &vert_obj[1];
|
||||
auto index_obj = &uv_obj[1];
|
||||
|
||||
*vert_obj = (qfv_resobj_t) {
|
||||
.name = "vertex",
|
||||
.type = qfv_res_buffer,
|
||||
.buffer = {
|
||||
.size = vert_size,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
},
|
||||
};
|
||||
dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer,
|
||||
vbuff, 1, ©_region[0]);
|
||||
dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer,
|
||||
uvbuff, 1, ©_region[1]);
|
||||
dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer,
|
||||
ibuff, 1, ©_region[2]);
|
||||
// both qfv_BB_TransferWrite_to_VertexAttrRead and
|
||||
// qfv_BB_TransferWrite_to_IndexRead have the same stage flags
|
||||
bb = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead];
|
||||
VkBufferMemoryBarrier rd_barriers[] = {
|
||||
bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead].barrier,
|
||||
bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead].barrier,
|
||||
bufferBarriers[qfv_BB_TransferWrite_to_IndexRead].barrier,
|
||||
*uv_obj = (qfv_resobj_t) {
|
||||
.name = "uv",
|
||||
.type = qfv_res_buffer,
|
||||
.buffer = {
|
||||
.size = uv_size,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
},
|
||||
};
|
||||
rd_barriers[0].buffer = vbuff;
|
||||
rd_barriers[0].size = vert_size;
|
||||
rd_barriers[1].buffer = uvbuff;
|
||||
rd_barriers[1].size = uv_size;
|
||||
rd_barriers[2].buffer = ibuff;
|
||||
rd_barriers[2].size = ind_size;
|
||||
dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages,
|
||||
0, 0, 0, 3, rd_barriers, 0, 0);
|
||||
*index_obj = (qfv_resobj_t) {
|
||||
.name = "index",
|
||||
.type = qfv_res_buffer,
|
||||
.buffer = {
|
||||
.size = ind_size,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
},
|
||||
};
|
||||
QFV_CreateResource (device, mesh->resources);
|
||||
mesh->vertex_buffer = vert_obj->buffer.buffer;
|
||||
mesh->uv_buffer = uv_obj->buffer.buffer;
|
||||
mesh->index_buffer = index_obj->buffer.buffer;
|
||||
|
||||
size_t packet_size = vert_size + uv_size + ind_size;
|
||||
auto packet = QFV_PacketAcquire (ctx->staging);
|
||||
byte *packet_start = QFV_PacketExtend (packet, packet_size);
|
||||
byte *packet_data = packet_start;
|
||||
|
||||
qfv_scatter_t vert_scatter = {
|
||||
.srcOffset = packet_data - packet_start,
|
||||
.dstOffset = 0,
|
||||
.length = vert_size,
|
||||
};
|
||||
auto verts = (aliasvrt_t *) packet_data;
|
||||
packet_data += vert_scatter.length;
|
||||
build_verts (verts, hdr->numposes, numverts, &hdr->mdl,
|
||||
indexmap, alias_ctx);
|
||||
|
||||
qfv_scatter_t uv_scatter = {
|
||||
.srcOffset = packet_data - packet_start,
|
||||
.dstOffset = 0,
|
||||
.length = uv_size,
|
||||
};
|
||||
auto uv = (aliasuv_t *) packet_data;
|
||||
packet_data += uv_scatter.length;
|
||||
build_uvs (uv, &hdr->mdl, indexmap, alias_ctx);
|
||||
|
||||
qfv_scatter_t ind_scatter = {
|
||||
.srcOffset = packet_data - packet_start,
|
||||
.dstOffset = 0,
|
||||
.length = ind_size,
|
||||
};
|
||||
auto indices = (uint32_t *) packet_data;
|
||||
packet_data += ind_scatter.length;
|
||||
build_inds (indices, hdr->mdl.numtris, indexmap, alias_ctx);
|
||||
|
||||
QFV_PacketScatterBuffer (packet, mesh->vertex_buffer, 1, &vert_scatter,
|
||||
&bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]);
|
||||
QFV_PacketScatterBuffer (packet, mesh->uv_buffer, 1, &uv_scatter,
|
||||
&bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]);
|
||||
QFV_PacketScatterBuffer (packet, mesh->index_buffer, 1, &ind_scatter,
|
||||
&bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]);
|
||||
QFV_PacketSubmit (packet);
|
||||
QFV_DestroyStagingBuffer (stage);
|
||||
}
|
||||
|
||||
void
|
||||
Vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m,
|
||||
int _s, int extra, vulkan_ctx_t *ctx)
|
||||
{
|
||||
aliashdr_t *header = alias_ctx->header;
|
||||
|
||||
if (header->mdl.ident == HEADER_MDL16)
|
||||
VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale);
|
||||
|
||||
qfv_alias_mesh_t *mesh = Hunk_Alloc (0, sizeof (qfv_alias_mesh_t));
|
||||
mesh->vertex_buffer = vbuff;
|
||||
mesh->uv_buffer = uvbuff;
|
||||
mesh->index_buffer = ibuff;
|
||||
mesh->memory = mem;
|
||||
header->commands = (byte *) mesh - (byte *) header;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue