From 119e9766b90723561ef4da8029317290dbce8135 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jan 2024 13:36:46 +0900 Subject: [PATCH] [iqm] Use 32-bit indices for large models That is, those with more than 65520 vertices. Not properly supported for sw or gl, and glsl isn't rendering properly for some reason (renderdoc does see the meshes, though, so maybe depth or winding issues). --- include/QF/iqm.h | 5 ++++- libs/models/iqm/glsl_model_iqm.c | 7 ++++--- libs/models/iqm/model_iqm.c | 16 +++++++++++----- libs/models/iqm/sw_model_iqm.c | 8 ++++---- libs/models/iqm/vulkan_model_iqm.c | 11 +++++++++-- libs/video/renderer/gl/gl_mod_iqm.c | 2 +- libs/video/renderer/glsl/glsl_iqm.c | 13 ++++++++++--- libs/video/renderer/sw/sw_riqm.c | 4 ++-- libs/video/renderer/vulkan/vulkan_iqm.c | 5 +++-- 9 files changed, 48 insertions(+), 23 deletions(-) diff --git a/include/QF/iqm.h b/include/QF/iqm.h index 8d99895c5..9f2b46514 100644 --- a/include/QF/iqm.h +++ b/include/QF/iqm.h @@ -135,7 +135,10 @@ typedef struct iqm_s { byte *vertices; int stride; int num_elements; - uint16_t *elements; + union { + uint16_t *elements16; + uint32_t *elements32; + }; int num_arrays; iqmvertexarray *vertexarrays; int num_joints; diff --git a/libs/models/iqm/glsl_model_iqm.c b/libs/models/iqm/glsl_model_iqm.c index 9f7a75ee6..0d42cf9c7 100644 --- a/libs/models/iqm/glsl_model_iqm.c +++ b/libs/models/iqm/glsl_model_iqm.c @@ -130,15 +130,16 @@ glsl_iqm_load_arrays (iqm_t *iqm) qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, glsl->element_array); qfeglBufferData (GL_ARRAY_BUFFER, iqm->num_verts * iqm->stride, iqm->vertices, GL_STATIC_DRAW); + int esize = iqm->num_verts > 0xfff0 ? sizeof (uint32_t) : sizeof (uint16_t); qfeglBufferData (GL_ELEMENT_ARRAY_BUFFER, - iqm->num_elements * sizeof (uint16_t), iqm->elements, + iqm->num_elements * esize, iqm->elements16, GL_STATIC_DRAW); qfeglBindBuffer (GL_ARRAY_BUFFER, 0); qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); free (iqm->vertices); iqm->vertices = 0; - free (iqm->elements); - iqm->elements = 0; + free (iqm->elements16); + iqm->elements16 = 0; } void diff --git a/libs/models/iqm/model_iqm.c b/libs/models/iqm/model_iqm.c index 566c1eefa..b1ef3355f 100644 --- a/libs/models/iqm/model_iqm.c +++ b/libs/models/iqm/model_iqm.c @@ -344,9 +344,15 @@ load_iqm_meshes (model_t *mod, const iqmheader *hdr, byte *buffer) if (!(tris = get_triangles (hdr, buffer))) return false; iqm->num_elements = hdr->num_triangles * 3; - iqm->elements = malloc (hdr->num_triangles * 3 * sizeof (uint16_t)); - for (i = 0; i < hdr->num_triangles; i++) - VectorCopy (tris[i].vertex, iqm->elements + i * 3); + if (iqm->num_verts > 0xfff0) { + iqm->elements32 = malloc (hdr->num_triangles * 3 * sizeof (uint32_t)); + for (i = 0; i < hdr->num_triangles; i++) + VectorCopy (tris[i].vertex, iqm->elements32 + i * 3); + } else { + iqm->elements16 = malloc (hdr->num_triangles * 3 * sizeof (uint16_t)); + for (i = 0; i < hdr->num_triangles; i++) + VectorCopy (tris[i].vertex, iqm->elements16 + i * 3); + } if (!(meshes = get_meshes (hdr, buffer))) return false; iqm->num_meshes = hdr->num_meshes; @@ -528,8 +534,8 @@ Mod_FreeIQM (iqm_t *iqm) if (iqm->vertices) free (iqm->vertices); free (iqm->vertexarrays); - if (iqm->elements) - free (iqm->elements); + if (iqm->elements16) + free (iqm->elements16); free (iqm->meshes); free (iqm->joints); free (iqm->baseframe); diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index 0e6d1fa48..3ae8764b3 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -124,7 +124,7 @@ sw_iqm_load_textures (iqm_t *iqm) tex = sw->skins[i] = &null_texture; for (j = 0; j < (int) iqm->meshes[i].num_triangles * 3; j++) { int ind = iqm->meshes[i].first_triangle * 3 + j; - int vind = iqm->elements[ind]; + int vind = iqm->elements16[ind]; byte *vert = iqm->vertices + iqm->stride * vind; byte *tc = vert + sw->texcoord->offset; @@ -150,10 +150,10 @@ sw_iqm_convert_tris (iqm_t *iqm) tris = malloc (num_tris * sizeof (mtriangle_t)); for (i = 0; i < num_tris; i++) { tris[i].facesfront = 1; - VectorCopy (iqm->elements + i * 3, tris[i].vertindex); + VectorCopy (iqm->elements16 + i * 3, tris[i].vertindex); } - free (iqm->elements); - iqm->elements = (uint16_t *) tris; + free (iqm->elements16); + iqm->elements16 = (uint16_t *) tris; } void diff --git a/libs/models/iqm/vulkan_model_iqm.c b/libs/models/iqm/vulkan_model_iqm.c index 297d1f592..8a1e64d63 100644 --- a/libs/models/iqm/vulkan_model_iqm.c +++ b/libs/models/iqm/vulkan_model_iqm.c @@ -225,6 +225,9 @@ vulkan_iqm_load_arrays (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh, size_t geom_size = iqm->num_verts * sizeof (iqmgvert_t); size_t rend_size = iqm->num_verts * sizeof (iqmrvert_t); size_t elem_size = iqm->num_elements * sizeof (uint16_t); + if (iqm->num_verts > 0xfff0) { + elem_size = iqm->num_elements * sizeof (uint32_t); + } size_t buff_size = geom_size + rend_size + elem_size + 1024; qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, va (ctx->va_ctx, "iqm:%s", @@ -282,7 +285,7 @@ vulkan_iqm_load_arrays (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh, data += size; } } - memcpy (elements, iqm->elements, elem_size); + memcpy (elements, iqm->elements16, elem_size); qfv_bufferbarrier_t bb[] = { bufferBarriers[qfv_BB_Unknown_to_TransferWrite], @@ -417,11 +420,15 @@ Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx) | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, }, }; + size_t elem_size = iqm->num_elements * sizeof (uint16_t); + if (iqm->num_verts > 0xfff0) { + elem_size = iqm->num_elements * sizeof (uint32_t); + } mesh->mesh->objects[2] = (qfv_resobj_t) { .name = "index", .type = qfv_res_buffer, .buffer = { - .size = iqm->num_elements * sizeof (uint16_t), + .size = elem_size, .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, }, diff --git a/libs/video/renderer/gl/gl_mod_iqm.c b/libs/video/renderer/gl/gl_mod_iqm.c index 94cfd80eb..109f777d4 100644 --- a/libs/video/renderer/gl/gl_mod_iqm.c +++ b/libs/video/renderer/gl/gl_mod_iqm.c @@ -65,7 +65,7 @@ gl_draw_iqm_frame (iqm_t *iqm, gliqm_t *gl, iqmframe_t *frame, iqmmesh *mesh) for (i = 0; i < mesh->num_triangles; i++) { int vind = (mesh->first_triangle + i) * 3; for (j = 0; j < 3; j++) { - vert = iqm->vertices + iqm->elements[vind + j] * iqm->stride; + vert = iqm->vertices + iqm->elements16[vind + j] * iqm->stride; if (gl->texcoord) qfglTexCoord2fv ((float *) (vert + gl->texcoord->offset)); if (gl->color) diff --git a/libs/video/renderer/glsl/glsl_iqm.c b/libs/video/renderer/glsl/glsl_iqm.c index a70b7cb08..d7f8b7fd0 100644 --- a/libs/video/renderer/glsl/glsl_iqm.c +++ b/libs/video/renderer/glsl/glsl_iqm.c @@ -269,9 +269,16 @@ glsl_R_DrawIQM (entity_t ent) qfeglBindTexture (GL_TEXTURE_2D, glsl->textures[i]); qfeglActiveTexture (GL_TEXTURE0 + 1); qfeglBindTexture (GL_TEXTURE_2D, glsl->normmaps[i]); - qfeglDrawElements (GL_TRIANGLES, 3 * iqm->meshes[i].num_triangles, - GL_UNSIGNED_SHORT, - iqm->elements + 3 * iqm->meshes[i].first_triangle); + int firstElement = 3 * iqm->meshes[i].first_triangle; + if (iqm->num_verts > 0xfff0) { + qfeglDrawElements (GL_TRIANGLES, 3 * iqm->meshes[i].num_triangles, + GL_UNSIGNED_INT, + iqm->elements32 + firstElement); + } else { + qfeglDrawElements (GL_TRIANGLES, 3 * iqm->meshes[i].num_triangles, + GL_UNSIGNED_SHORT, + iqm->elements16 + firstElement); + } } } diff --git a/libs/video/renderer/sw/sw_riqm.c b/libs/video/renderer/sw/sw_riqm.c index 06c0e8882..9ba26d2c9 100644 --- a/libs/video/renderer/sw/sw_riqm.c +++ b/libs/video/renderer/sw/sw_riqm.c @@ -145,7 +145,7 @@ R_IQMPrepareUnclippedPoints (iqm_t *iqm, swiqm_t *sw, iqmframe_t *frame) iqm_setup_skin (sw, i); - tris = iqm->elements + mesh->first_triangle; + tris = iqm->elements16 + mesh->first_triangle; r_affinetridesc.ptriangles = (mtriangle_t *) tris; r_affinetridesc.numtriangles = mesh->num_triangles; D_PolysetDraw (); @@ -187,7 +187,7 @@ R_IQMPreparePoints (iqm_t *iqm, swiqm_t *sw, iqmframe_t *frame) iqm_setup_skin (sw, i); - mtri = (mtriangle_t *) iqm->elements + mesh->first_triangle; + mtri = (mtriangle_t *) iqm->elements16 + mesh->first_triangle; r_affinetridesc.numtriangles = 1; for (j = 0; j < mesh->num_triangles; j++, mtri++) { pfv[0] = &pfinalverts[mtri->vertindex[0]]; diff --git a/libs/video/renderer/vulkan/vulkan_iqm.c b/libs/video/renderer/vulkan/vulkan_iqm.c index f8efa5fe3..54738095c 100644 --- a/libs/video/renderer/vulkan/vulkan_iqm.c +++ b/libs/video/renderer/vulkan/vulkan_iqm.c @@ -86,8 +86,9 @@ emit_commands (VkCommandBuffer cmd, int pose1, int pose2, Vulkan_BeginEntityLabel (ctx, cmd, ent); dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets); - dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0, - VK_INDEX_TYPE_UINT16); + VkIndexType indexType = iqm->num_verts > 0xfff0 ? VK_INDEX_TYPE_UINT32 + : VK_INDEX_TYPE_UINT16; + dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0, indexType); QFV_PushConstants (device, cmd, layout, numPC, constants); for (int i = 0; i < iqm->num_meshes; i++) { if (skins) {