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) {