From 56715e6796993fff95e3603cdee310cde5c72bd2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 02:35:03 +0900 Subject: [PATCH 01/77] Fix a typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d36cd9d8..f0f4e2f55 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Vulkan (very WIP), all within the one executable. Dedicated servers for both Quake (nq-server) and QuakeWorld (qw-server) are included, as well as a master server for QuakeWorld (qw-master). -## Tool +## Tools QuakeForge includes several tools for working with Quake data: - bsp2image produces wireframe images from Quake maps (bsp files) From 6d0abd42bb84e92c94d5ec07d6dad2e2d765acb1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 15:14:56 +0900 Subject: [PATCH 02/77] [vulkan] Use host-cached memory for staging buffers It makes a significant difference to level load times (approximately halves them for demo1 and demo2). Nicely, it turns out I had implemented the rest of the staging buffer code (in particular, flushing) correctly in that it seems there's no corruption any of the data. --- libs/video/renderer/vulkan/staging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 660e61a64..e16aa49df 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -55,7 +55,7 @@ QFV_CreateStagingBuffer (qfv_device_t *device, const char *name, size_t size, QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, stage->buffer, dsprintf (str, "staging:buffer:%s", name)); stage->memory = QFV_AllocBufferMemory (device, stage->buffer, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, size, 0); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, stage->memory, dsprintf (str, "staging:memory:%s", name)); From 42a03758c50b5e38f018b6e1fee6fcbaa4e764b1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 15:25:52 +0900 Subject: [PATCH 03/77] [vulkan] Remove redundant entity queue creation I'd missed this when cleaning up entity queue creation for the other renderers. --- libs/video/renderer/vid_render_vulkan.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 9c65ef615..2b056e7b1 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -80,7 +80,6 @@ vulkan_ParticleSystem (void) static void vulkan_R_Init (void) { - r_ent_queue = EntQueue_New (mod_num_types); Vulkan_CreateStagingBuffers (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); Vulkan_CreateFrames (vulkan_ctx); From 6bbbe4997bde7e6260aca317141c60368f6377ef Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 16:19:10 +0900 Subject: [PATCH 04/77] [vulkan] Invalidate mapped capture image memory I think I had gotten lucky with captures not being corrupt due to them being much bigger than all but the L3 cache (and then they're over 1/2 the size), so the memory was being automatically invalidated by other activity. Don't want to trust such luck, though. --- include/QF/Vulkan/capture.h | 2 ++ include/QF/Vulkan/funclist.h | 1 + libs/video/renderer/vulkan/capture.c | 22 +++++++++++++++------- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/QF/Vulkan/capture.h b/include/QF/Vulkan/capture.h index a2fa1397b..6cfd9d47e 100644 --- a/include/QF/Vulkan/capture.h +++ b/include/QF/Vulkan/capture.h @@ -23,7 +23,9 @@ typedef struct qfv_capture_s { int canBlit; VkExtent2D extent; qfv_capture_image_set_t *image_set; + size_t imgsize; size_t memsize; + byte *data; VkDeviceMemory memory; } qfv_capture_t; diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 1dec3bcc3..94189143d 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -131,6 +131,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkMapMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkUnmapMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkFlushMappedMemoryRanges) +DEVICE_LEVEL_VULKAN_FUNCTION (vkInvalidateMappedMemoryRanges) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateSampler) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateDescriptorSetLayout) diff --git a/libs/video/renderer/vulkan/capture.c b/libs/video/renderer/vulkan/capture.c index a7c190fe9..d11ea7ad9 100644 --- a/libs/video/renderer/vulkan/capture.c +++ b/libs/video/renderer/vulkan/capture.c @@ -99,22 +99,21 @@ QFV_CreateCapture (qfv_device_t *device, int numframes, image->layout = VK_IMAGE_LAYOUT_UNDEFINED; image->cmd = cmdset->a[i]; } - size_t image_size = QFV_GetImageSize (device, - capture->image_set->a[0].image); - capture->memsize = numframes * image_size; + capture->imgsize = QFV_GetImageSize (device, + capture->image_set->a[0].image); + capture->memsize = numframes * capture->imgsize; capture->memory = QFV_AllocImageMemory (device, capture->image_set->a[0].image, VK_MEMORY_PROPERTY_HOST_CACHED_BIT, capture->memsize, 0); - byte *data; dfunc->vkMapMemory (device->dev, capture->memory, 0, capture->memsize, 0, - (void **) &data); + (void **) &capture->data); for (int i = 0; i < numframes; i++) { __auto_type image = &capture->image_set->a[i]; - image->data = data + i * image_size; + image->data = capture->data + i * capture->imgsize; dfunc->vkBindImageMemory (device->dev, image->image, capture->memory, - image->data - data); + image->data - capture->data); } return capture; } @@ -252,6 +251,15 @@ QFV_CaptureImage (qfv_capture_t *capture, VkImage scImage, int frame) const byte * QFV_CaptureData (qfv_capture_t *capture, int frame) { + qfv_device_t *device = capture->device; + qfv_devfuncs_t *dfunc = device->funcs; __auto_type image = &capture->image_set->a[frame]; + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = capture->memory, + .offset = image->data - capture->data, + .size = capture->imgsize, + }; + dfunc->vkInvalidateMappedMemoryRanges (device->dev, 1, &range); return image->data; } From 03c403610dd77887dd5a06886009a8871e598283 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 16:49:39 +0900 Subject: [PATCH 05/77] [vulkan] Safely ignore fisheye and water warp I didn't like the abort (especially having pushed it to master). This takes care of things until I can get them implemented properly (hopefully soon). --- libs/video/renderer/r_screen.c | 2 +- libs/video/renderer/vid_render_vulkan.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 86608c069..cabd491cc 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -288,7 +288,7 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs) if (r_dowarp) { r_funcs->bind_framebuffer (warp_buffer); } - if (scr_fisheye->int_val) { + if (scr_fisheye->int_val && fisheye_cube_map) { int side = fisheye_cube_map->width; vrect_t feye = { 0, 0, side, side }; r_funcs->set_viewport (&feye); diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 2b056e7b1..94ffcc987 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -429,13 +429,13 @@ vulkan_end_frame (void) static framebuffer_t * vulkan_create_cube_map (int size) { - Sys_Error ("not implemented"); + return 0; } static framebuffer_t * vulkan_create_frame_buffer (int width, int height) { - Sys_Error ("not implemented"); + return 0; } static void From 11e30583cf9580e8cf82972dff29dd87ddfb0f1c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 19:50:41 +0900 Subject: [PATCH 06/77] [vulkan] Switch to full screen triangle instead of quad While I have trouble imagining it making that much performance difference going from 4 verts to 3 for a whopping 2 polygons, or even from 2 triangles to 1 for each poly, using only indices for the vertices does remove a lot of code, and better yet, some memory and buffer allocations... always a good thing. That said, I guess freeing up a GPU thread for something else could make a difference. --- include/QF/Vulkan/qf_vid.h | 4 +- include/vid_vulkan.h | 3 -- libs/video/renderer/Makemodule.am | 6 +++ libs/video/renderer/vulkan/qfpipeline.plist | 28 ++++++------- libs/video/renderer/vulkan/shader.c | 3 ++ .../renderer/vulkan/shader/fstriangle.vert | 9 +++++ libs/video/renderer/vulkan/vulkan_compose.c | 4 +- libs/video/renderer/vulkan/vulkan_lighting.c | 4 +- .../video/renderer/vulkan/vulkan_vid_common.c | 40 ------------------- 9 files changed, 34 insertions(+), 67 deletions(-) create mode 100644 libs/video/renderer/vulkan/shader/fstriangle.vert diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index f729c2b65..bf76b13d2 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -40,8 +40,8 @@ typedef enum { QFV_passDepth, // geometry QFV_passTranslucent, // geometry QFV_passGBuffer, // geometry - QFV_passLighting, // single quad - QFV_passCompose, // single quad + QFV_passLighting, // single triangle + QFV_passCompose, // single triangle QFV_NumPasses } QFV_Subpass; diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 56aa8c3f3..7778dda83 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -66,9 +66,6 @@ typedef struct vulkan_ctx_s { struct lightingctx_s *lighting_context; struct composectx_s *compose_context; - VkBuffer quad_buffer; - VkDeviceMemory quad_memory; - VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index bc48a77e2..2743a4a68 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -301,6 +301,8 @@ alias_shadow_src = $(vkshaderpath)/alias_shadow.vert alias_shadow_c = $(vkshaderpath)/alias_shadow.vert.spvc passthrough_src = $(vkshaderpath)/passthrough.vert passthrough_c = $(vkshaderpath)/passthrough.vert.spvc +fstriangle_src = $(vkshaderpath)/fstriangle.vert +fstriangle_c = $(vkshaderpath)/fstriangle.vert.spvc pushcolor_src = $(vkshaderpath)/pushcolor.frag pushcolor_c = $(vkshaderpath)/pushcolor.frag.spvc shadow_src = $(vkshaderpath)/shadow.geom @@ -358,6 +360,8 @@ $(alias_shadow_c): $(alias_shadow_src) $(passthrough_c): $(passthrough_src) +$(fstriangle_c): $(fstriangle_src) + $(pushcolor_c): $(pushcolor_src) $(shadow_c): $(shadow_src) @@ -391,6 +395,7 @@ vkshader_c = \ $(alias_gbuf_c) \ $(alias_shadow_c) \ $(passthrough_c) \ + $(fstriangle_c) \ $(pushcolor_c) \ $(shadow_c) @@ -443,6 +448,7 @@ EXTRA_DIST += \ libs/video/renderer/vulkan/shader/compose.frag \ libs/video/renderer/vulkan/shader/lighting.frag \ libs/video/renderer/vulkan/shader/passthrough.vert \ + libs/video/renderer/vulkan/shader/fstriangle.vert \ libs/video/renderer/vulkan/shader/partphysics.comp \ libs/video/renderer/vulkan/shader/partupdate.comp \ libs/video/renderer/vulkan/shader/particle.vert \ diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 40a28a89a..876613b98 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -559,17 +559,13 @@ }; }; - fsquad = { + fstriangle = { vertexInput = { - bindings = ( - { binding = 0; stride = "4 * 4"; inputRate = vertex; }, - ); - attributes = ( - { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, - ); + bindings = (); + attributes = (); }; inputAssembly = { - topology = triangle_strip; + topology = triangle_list; primitiveRestartEnable = false; }; colorBlend = { @@ -1008,7 +1004,7 @@ { stage = vertex; name = main; - module = $builtin/passthrough.vert; + module = $builtin/fstriangle.vert; }, { stage = fragment; @@ -1022,13 +1018,13 @@ }; }, ); - vertexInput = $properties.fsquad.vertexInput; - inputAssembly = $properties.fsquad.inputAssembly; + vertexInput = $properties.fstriangle.vertexInput; + inputAssembly = $properties.fstriangle.inputAssembly; viewport = $properties.viewport; rasterization = $properties.rasterization.counter_cw_cull_back; multisample = $properties.multisample; depthStencil = $properties.depthStencil.disable; - colorBlend = $properties.fsquad.colorBlend; + colorBlend = $properties.fstriangle.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; @@ -1041,7 +1037,7 @@ { stage = vertex; name = main; - module = $builtin/passthrough.vert; + module = $builtin/fstriangle.vert; }, { stage = fragment; @@ -1049,13 +1045,13 @@ module = $builtin/compose.frag; }, ); - vertexInput = $properties.fsquad.vertexInput; - inputAssembly = $properties.fsquad.inputAssembly; + vertexInput = $properties.fstriangle.vertexInput; + inputAssembly = $properties.fstriangle.inputAssembly; viewport = $properties.viewport; rasterization = $properties.rasterization.counter_cw_cull_back; multisample = $properties.multisample; depthStencil = $properties.depthStencil.disable; - colorBlend = $properties.fsquad.colorBlend; + colorBlend = $properties.fstriangle.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index a71c83300..8cab2d8a6 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -95,6 +95,8 @@ static static #include "libs/video/renderer/vulkan/shader/passthrough.vert.spvc" static +#include "libs/video/renderer/vulkan/shader/fstriangle.vert.spvc" +static #include "libs/video/renderer/vulkan/shader/pushcolor.frag.spvc" static #include "libs/video/renderer/vulkan/shader/shadow.geom.spvc" @@ -134,6 +136,7 @@ static shaderdata_t builtin_shaders[] = { { "alias_gbuf.frag", alias_gbuf_frag, sizeof (alias_gbuf_frag) }, { "alias_shadow.vert", alias_shadow_vert, sizeof (alias_shadow_vert) }, { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, + { "fstriangle.vert", fstriangle_vert, sizeof (fstriangle_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, { "shadow.geom", shadow_geom, sizeof (shadow_geom) }, {} diff --git a/libs/video/renderer/vulkan/shader/fstriangle.vert b/libs/video/renderer/vulkan/shader/fstriangle.vert new file mode 100644 index 000000000..66c55d6ac --- /dev/null +++ b/libs/video/renderer/vulkan/shader/fstriangle.vert @@ -0,0 +1,9 @@ +#version 450 + +void +main () +{ + float x = (gl_VertexIndex & 2); + float y = (gl_VertexIndex & 1); + gl_Position = vec4 (2, 4, 0, 1) * vec4 (x, y, 0, 1) - vec4 (1, 1, 0, 0); +} diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c index 161012ae0..9da079647 100644 --- a/libs/video/renderer/vulkan/vulkan_compose.c +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -105,9 +105,7 @@ Vulkan_Compose_Draw (qfv_renderframe_t *rFrame) dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); - VkDeviceSize offset = 0; - dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &ctx->quad_buffer, &offset); - dfunc->vkCmdDraw (cmd, 4, 1, 0, 0); + dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); QFV_duCmdEndLabel (device, cmd); dfunc->vkEndCommandBuffer (cmd); diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 83a8ee061..03a6b3501 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -260,9 +260,7 @@ Vulkan_Lighting_Draw (qfv_renderframe_t *rFrame) dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); - VkDeviceSize offset = 0; - dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &ctx->quad_buffer, &offset); - dfunc->vkCmdDraw (cmd, 4, 1, 0, 0); + dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); QFV_duCmdEndLabel (device, cmd); dfunc->vkEndCommandBuffer (cmd); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index d5cbcfaf6..bfbc69e03 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -446,43 +446,6 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) rp->draw = renderpass_draw; DARRAY_APPEND (&ctx->renderPasses, rp); - - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - static float quad_vertices[] = { - -1, -1, 0, 1, - -1, 1, 0, 1, - 1, -1, 0, 1, - 1, 1, 0, 1, - }; - ctx->quad_buffer = QFV_CreateBuffer (device, sizeof (quad_vertices), - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT - | VK_BUFFER_USAGE_TRANSFER_DST_BIT); - ctx->quad_memory = QFV_AllocBufferMemory (device, ctx->quad_buffer, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - 0, 0); - QFV_BindBufferMemory (device, ctx->quad_buffer, ctx->quad_memory, 0); - - qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); - float *verts = QFV_PacketExtend (packet, sizeof (quad_vertices)); - memcpy (verts, quad_vertices, sizeof (quad_vertices)); - - qfv_bufferbarrier_t bb = bufferBarriers[qfv_BB_Unknown_to_TransferWrite]; - bb.barrier.buffer = ctx->quad_buffer; - bb.barrier.size = sizeof (quad_vertices); - dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages, - 0, 0, 0, 1, &bb.barrier, 0, 0); - VkBufferCopy copy_region[] = { - { packet->offset, 0, sizeof (quad_vertices) }, - }; - dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, - ctx->quad_buffer, 1, ©_region[0]); - bb = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]; - bb.barrier.buffer = ctx->quad_buffer; - bb.barrier.size = sizeof (quad_vertices); - dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages, - 0, 0, 0, 1, &bb.barrier, 0, 0); - QFV_PacketSubmit (packet); } static void @@ -542,9 +505,6 @@ Vulkan_DestroyRenderPasses (vulkan_ctx_t *ctx) free (rp); } - - dfunc->vkFreeMemory (device->dev, ctx->quad_memory, 0); - dfunc->vkDestroyBuffer (device->dev, ctx->quad_buffer, 0); } VkPipeline From 9892e571ce5afdaccd65dbf410c2a42079a26344 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Apr 2022 20:34:41 +0900 Subject: [PATCH 07/77] [vulkan] Move viewport and scissor into qfv_renderpass_t This makes much more sense as they are intimately tied to the frame buffer on which a render pass is working. Now, just the window width and height are stored in vulkan_ctx_t. As a side benefit, QFV_CreateSwapchain no long references viddef (now just palette and conview in vulkan_draw.c to go). --- include/QF/Vulkan/renderpass.h | 2 ++ include/vid_vulkan.h | 5 +++-- libs/video/renderer/vulkan/swapchain.c | 2 +- libs/video/renderer/vulkan/vulkan_alias.c | 6 +++--- libs/video/renderer/vulkan/vulkan_bsp.c | 4 ++-- libs/video/renderer/vulkan/vulkan_compose.c | 4 ++-- libs/video/renderer/vulkan/vulkan_draw.c | 4 ++-- libs/video/renderer/vulkan/vulkan_lighting.c | 4 ++-- libs/video/renderer/vulkan/vulkan_sprite.c | 4 ++-- libs/video/renderer/vulkan/vulkan_vid_common.c | 5 +++++ libs/video/targets/vid_x11_vulkan.c | 6 ++---- 11 files changed, 26 insertions(+), 20 deletions(-) diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h index 31ea607ca..5e3daaa26 100644 --- a/include/QF/Vulkan/renderpass.h +++ b/include/QF/Vulkan/renderpass.h @@ -70,6 +70,8 @@ typedef struct qfv_renderpass_s { VkDeviceMemory attachmentMemory; qfv_framebufferset_t *framebuffers; + VkViewport viewport; + VkRect2D scissor; qfv_renderframeset_t frames; diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 7778dda83..56516113f 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -85,8 +85,9 @@ typedef struct vulkan_ctx_s { struct qfv_tex_s *default_magenta; struct qfv_tex_s *default_magenta_array; - VkViewport viewport; - VkRect2D scissor; + // size of window + int window_width; + int window_height; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index 20766233a..aa09a6db6 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -62,7 +62,7 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) numImages = surfCaps.maxImageCount; } - VkExtent2D imageSize = {viddef.width, viddef.height}; + VkExtent2D imageSize = {ctx->window_width, ctx->window_height}; if (surfCaps.currentExtent.width == ~0u) { imageSize.width = bound (surfCaps.minImageExtent.width, imageSize.width, diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 95bc262fb..8da5de204 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -206,8 +206,8 @@ alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, }; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, 0, 1, sets, 0, 0); - dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -261,7 +261,7 @@ Vulkan_AliasDepthRange (qfv_renderframe_t *rFrame, aliasctx_t *actx = ctx->alias_context; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - VkViewport viewport = ctx->viewport; + VkViewport viewport = rFrame->renderpass->viewport; viewport.minDepth = minDepth; viewport.maxDepth = maxDepth; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a29ba4742..a6047f57b 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -853,8 +853,8 @@ bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline, dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); VkDeviceSize offsets[] = { 0 }; dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets); diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c index 9da079647..6d8ad105e 100644 --- a/libs/video/renderer/vulkan/vulkan_compose.c +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -102,8 +102,8 @@ Vulkan_Compose_Draw (qfv_renderframe_t *rFrame) dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cctx->layout, 0, 1, sets, 0, 0); - dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index a936f0b6f..24c11db91 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -840,8 +840,8 @@ Vulkan_FlushText (qfv_renderframe_t *rFrame) dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, dctx->pipeline); - dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); VkDeviceSize offsets[] = {dframe->vert_offset}; dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &dctx->vert_buffer, offsets); dfunc->vkCmdBindIndexBuffer (cmd, dctx->ind_buffer, 0, diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 03a6b3501..83e7e6fdc 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -257,8 +257,8 @@ Vulkan_Lighting_Draw (qfv_renderframe_t *rFrame) dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, lctx->layout, 0, 3, sets, 0, 0); - dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); diff --git a/libs/video/renderer/vulkan/vulkan_sprite.c b/libs/video/renderer/vulkan/vulkan_sprite.c index c01ddb329..b0d9866cd 100644 --- a/libs/video/renderer/vulkan/vulkan_sprite.c +++ b/libs/video/renderer/vulkan/vulkan_sprite.c @@ -168,8 +168,8 @@ sprite_begin_subpass (QFV_SpriteSubpass subpass, VkPipeline pipeline, }; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, sctx->layout, 0, 1, sets, 0, 0); - dfunc->vkCmdSetViewport (cmd, 0, 1, &ctx->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &ctx->scissor); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index bfbc69e03..193f09e12 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -432,6 +432,11 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) name)); } + int width = ctx->window_width; + int height = ctx->window_height; + rp->viewport = (VkViewport) { 0, 0, width, height, 0, 1 }; + rp->scissor = (VkRect2D) { {0, 0}, {width, height} }; + DARRAY_INIT (&rp->frames, 4); DARRAY_RESIZE (&rp->frames, ctx->frames.size); for (size_t i = 0; i < rp->frames.size; i++) { diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index 39bf90310..1e9d39087 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -194,10 +194,8 @@ x11_vulkan_create_surface (vulkan_ctx_t *ctx) .window = pres->window }; - int width = viddef.width; - int height = viddef.height; - ctx->viewport = (VkViewport) { 0, 0, width, height, 0, 1 }; - ctx->scissor = (VkRect2D) { {0, 0}, {width, height} }; + ctx->window_width = viddef.width; + ctx->window_height = viddef.height; if (pres->vkCreateXlibSurfaceKHR (inst, &createInfo, 0, &surface) != VK_SUCCESS) { From 9b11992de4abcfc6cee6fb04b9ceb2d5de163d11 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 2 Apr 2022 10:53:23 +0900 Subject: [PATCH 08/77] [plist] Fix some typos and improve plfield_t's docs --- include/QF/plist.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/include/QF/plist.h b/include/QF/plist.h index c83f8d5a3..72b09682b 100644 --- a/include/QF/plist.h +++ b/include/QF/plist.h @@ -67,12 +67,12 @@ struct plfield_s; dictionary objects. If null, then the default parser for the object type is used: - * QFString: the point to the actual string. The string continues - to be owned by the string object. + * QFString: pointer to the actual string. The string continues to + be owned by the string object. * QFBinary: pointer to fixed-size DARRAY_TYPE(byte) (so size isn't lost) * QFArray: pointer to fixed-size DARRAY_TYPE(plitem_t *) with the - indivisual objects. The individual objects continue to be owned + individual objects. The individual objects continue to be owned by the array object. * QFDictionary: pointer to the hashtab_t hash table used for the dictionary object. The hash table continues to be owned by the @@ -86,7 +86,9 @@ struct plfield_s; checking is done: it is up to the top-level caller to parse out the messages. \param context Additional context data passed to the parser. - \return 0 for error, 1 for success. See \a PL_ParseDictionary. + \return 0 for error, 1 for success. See \a PL_ParseStruct, + \a PL_ParseArray, \a PL_ParseLabeledArray, and + \a PL_ParseSymtab. */ typedef int (*plparser_t) (const struct plfield_s *field, const struct plitem_s *item, @@ -96,7 +98,15 @@ typedef int (*plparser_t) (const struct plfield_s *field, /** A field to be parsed from a dictionary item. - something + \a PL_ParseStruct uses an array (terminated by an element with \a name + set to null) of these to describe the fields in the structure being + parsed. + + \a PL_ParseArray, \a PL_ParseLabeledArray, and \a PL_ParseSymtab use only + a single \a plfield_t object, and then only the \a data field, which must + point to a \a plelement_t object. This allows all the parse functions to + be used directly as either a \a plfield_t or \a plelement_t object's + \a parser. */ typedef struct plfield_s { const char *name; ///< matched by dictionary key From bbbdc41af30b7c9bb093d75b07f53d85a71a6d6c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 2 Apr 2022 11:42:36 +0900 Subject: [PATCH 09/77] [vulkan] Break render pass parsing away from swapchain This allows a single render pass description to be used for both on-screen and off-screen targets. While Vulkan does allow a VkRenderPass to be used with any compatible frame buffer, and vkparse caches a VkRenderPass created from the same description, this allows the same description to be used for a compatible off-screen target without any dependence on the swapchain. However, there is a problem in the caching when it comes to targeting outputs with different formats. --- include/vid_vulkan.h | 10 ++ libs/video/renderer/vulkan/deferred.plist | 40 +++---- libs/video/renderer/vulkan/vkparse.c | 104 +++++------------- libs/video/renderer/vulkan/vkparse.h | 12 -- .../video/renderer/vulkan/vulkan_vid_common.c | 11 +- 5 files changed, 66 insertions(+), 111 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 56516113f..b23654ef5 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -9,6 +9,13 @@ #include "QF/darray.h" #include "QF/simd/types.h" +//FIXME name +typedef struct qfv_output_s { + VkExtent2D extent; + VkImageView view; + VkFormat format; +} qfv_output_t; + typedef struct vulkan_frame_s { VkFramebuffer framebuffer; VkFence fence; @@ -89,6 +96,9 @@ typedef struct vulkan_ctx_s { int window_width; int window_height; + //FIXME not sure I like it being here (also, type name) + qfv_output_t output; + #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index 1eade9e2e..c5ce13c0f 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -5,8 +5,8 @@ format = x8_d24_unorm_pack32; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -20,8 +20,8 @@ format = r8g8b8a8_unorm; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -35,8 +35,8 @@ format = r16g16b16a16_sfloat; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -50,8 +50,8 @@ format = r16g16b16a16_sfloat; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -65,8 +65,8 @@ format = r32g32b32a32_sfloat; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -80,8 +80,8 @@ format = r8g8b8a8_unorm; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -95,8 +95,8 @@ format = r8g8b8a8_unorm; samples = 1; extent = { - width = $swapchain.extent.width; - height = $swapchain.extent.height; + width = $output.extent.width; + height = $output.extent.height; depth = 1; }; mipLevels = 1; @@ -223,9 +223,9 @@ framebuffer = { renderPass = $properties.renderpass; attachments = (depth, color, emission, normal, position, opaque, - translucent, "$swapchain.views[$swapImageIndex]"); - width = $swapchain.extent.width; - height = $swapchain.extent.height; + translucent, $output.view); + width = $output.extent.width; + height = $output.extent.height; layers = 1; }; clearValues = ( @@ -236,7 +236,7 @@ { color = "[0, 0, 0, 1]"; }, // position { color = "[0, 0, 0, 1]"; }, // opaque { color = "[0, 0, 0, 0]"; }, // translucent - { color = "[0, 0, 0, 1]"; }, // swapchain + { color = "[0, 0, 0, 1]"; }, // output ); renderpass = { attachments = ( @@ -311,7 +311,7 @@ finalLayout = color_attachment_optimal; }, { - format = $swapchain.format; + format = $output.format; samples = 1; loadOp = clear; storeOp = store; @@ -414,7 +414,7 @@ }, ); colorAttachments = ( - { // swapchain + { // output attachment = 7; layout = color_attachment_optimal; }, diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 79c6811e3..97fdd813d 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -42,8 +42,8 @@ #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/pipeline.h" +#include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/shader.h" -#include "QF/Vulkan/swapchain.h" #include "vid_vulkan.h" @@ -51,6 +51,17 @@ #include "vkparse.h" #undef vkparse_internal +typedef struct parseres_s { + const char *name; + plfield_t *field; + size_t offset; +} parseres_t; + +typedef struct handleref_s { + char *name; + uint64_t handle; +} handleref_t; + static void flag_or (const exprval_t *val1, const exprval_t *val2, exprval_t *result, exprctx_t *ctx) { @@ -577,7 +588,7 @@ parse_VkImage (const plitem_t *item, void **data, plitem_t *messages, return ret; } -static exprtype_t imageview_type = { +exprtype_t VkImageView_type = { "VkImageView", sizeof (VkImageView), 0, 0, 0 @@ -610,7 +621,7 @@ parse_VkImageView (const plfield_t *field, const plitem_t *item, void *data, plitem_t *imageViewItem = 0; if (ret) { VkImageView imageView; - if (value->type == &imageview_type) { + if (value->type == &VkImageView_type) { imageView = *(VkImageView *) value->value; } else if (value->type == &cexpr_plitem) { imageView = QFV_ParseImageView (ctx, imageViewItem, @@ -856,82 +867,21 @@ parse_specialization_data (const plitem_t *item, void **data, #include "libs/video/renderer/vulkan/vkparse.cinc" -static void -imageviewset_index (const exprval_t *a, size_t index, exprval_t *c, - exprctx_t *ctx) -{ - __auto_type set = *(qfv_imageviewset_t **) a->value; - exprval_t *val = 0; - if (index >= set->size) { - cexpr_error (ctx, "invalid index: %zd", index); - } else { - val = cexpr_value (&imageview_type, ctx); - *(VkImageView *) val->value = set->a[index]; - } - *(exprval_t **) c->value = val; -} - -static void -imageviewset_int (const exprval_t *a, const exprval_t *b, exprval_t *c, - exprctx_t *ctx) -{ - size_t index = *(int *) b->value; - imageviewset_index (a, index, c, ctx); -} - -static void -imageviewset_uint (const exprval_t *a, const exprval_t *b, exprval_t *c, - exprctx_t *ctx) -{ - size_t index = *(unsigned *) b->value; - imageviewset_index (a, index, c, ctx); -} - -static void -imageviewset_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c, - exprctx_t *ctx) -{ - size_t index = *(size_t *) b->value; - imageviewset_index (a, index, c, ctx); -} - -binop_t imageviewset_binops[] = { - { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_pointer_getfield }, - { '[', &cexpr_int, &imageview_type, imageviewset_int }, - { '[', &cexpr_uint, &imageview_type, imageviewset_uint }, - { '[', &cexpr_size_t, &imageview_type, imageviewset_size_t }, - {} -}; - -static exprsym_t imageviewset_symbols[] = { - {"size", &cexpr_size_t, (void *)field_offset (qfv_imageviewset_t, size)}, +static exprsym_t qfv_output_t_symbols[] = { + {"format", &VkFormat_type, (void *)field_offset (qfv_output_t, format)}, + {"extent", &VkExtent2D_type, (void *)field_offset (qfv_output_t, extent)}, + {"view", &VkImageView_type, (void *)field_offset (qfv_output_t, view)}, { } }; -static exprtab_t imageviewset_symtab = { - imageviewset_symbols, +static exprtab_t qfv_output_t_symtab = { + qfv_output_t_symbols, }; -exprtype_t imageviewset_type = { - "imageviewset", - sizeof (qfv_imageviewset_t *), - imageviewset_binops, - 0, - &imageviewset_symtab, -}; -static exprsym_t qfv_swapchain_t_symbols[] = { - {"format", &VkFormat_type, (void *)field_offset (qfv_swapchain_t, format)}, - {"extent", &VkExtent2D_type, (void *)field_offset (qfv_swapchain_t, extent)}, - {"views", &imageviewset_type, (void *)field_offset (qfv_swapchain_t, imageViews)}, - { } -}; -static exprtab_t qfv_swapchain_t_symtab = { - qfv_swapchain_t_symbols, -}; -exprtype_t qfv_swapchain_t_type = { - "qfv_swapchain_t", - sizeof (qfv_swapchain_t), +exprtype_t qfv_output_t_type = { + "qfv_output_t", + sizeof (qfv_output_t), cexpr_struct_binops, 0, - &qfv_swapchain_t_symtab, + &qfv_output_t_symtab, }; static exprsym_t vulkan_frameset_t_symbols[] = { @@ -1023,9 +973,8 @@ QFV_InitParse (vulkan_ctx_t *ctx) &ctx->hashlinks); context.hashlinks = &ctx->hashlinks; vkgen_init_symtabs (&context); - cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); + cexpr_init_symtab (&qfv_output_t_symtab, &context); cexpr_init_symtab (&vulkan_frameset_t_symtab, &context); - cexpr_init_symtab (&imageviewset_symtab, &context); cexpr_init_symtab (&data_array_symtab, &context); if (!ctx->setLayouts) { @@ -1054,10 +1003,9 @@ parse_object (vulkan_ctx_t *ctx, memsuper_t *memsuper, plitem_t *plist, exprctx_t exprctx = { .symtab = &root_symtab }; parsectx_t parsectx = { &exprctx, ctx, properties }; exprsym_t var_syms[] = { - {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"output", &qfv_output_t_type, &ctx->output}, {"frames", &vulkan_frameset_t_type, &ctx->frames}, {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {"swapImageIndex", &cexpr_uint, &ctx->swapImageIndex}, {"physDevLimits", &VkPhysicalDeviceLimits_type, &ctx->device->physDev->properties.limits }, {QFV_PROPERTIES, &cexpr_plitem, &parsectx.properties}, diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 6f2ea6357..730094e3b 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -10,24 +10,12 @@ typedef struct parsectx_s { #include "QF/cexpr.h" #include "QF/plist.h" -#include "QF/Vulkan/renderpass.h" #ifdef vkparse_internal #include "libs/video/renderer/vulkan/vkparse.hinc" #endif #define QFV_PROPERTIES "properties" -typedef struct parseres_s { - const char *name; - plfield_t *field; - size_t offset; -} parseres_t; - -typedef struct handleref_s { - char *name; - uint64_t handle; -} handleref_t; - void QFV_InitParse (vulkan_ctx_t *ctx); exprenum_t *QFV_GetEnum (const char *name); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 193f09e12..06ba768f0 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -388,7 +388,11 @@ create_attachements (vulkan_ctx_t *ctx, qfv_renderpass_t *rp) rp->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages, malloc); for (size_t i = 0; i < rp->framebuffers->size; i++) { - ctx->swapImageIndex = i; // for $swapImageIndex in the config + ctx->output = (qfv_output_t) { + .extent = ctx->swapchain->extent, + .view = ctx->swapchain->imageViews->a[i], + .format = ctx->swapchain->format, + }; rp->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item, rp->renderpassDef); } @@ -424,6 +428,11 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) if (renderpass) { rp->renderpass = renderpass; } else { + ctx->output = (qfv_output_t) { + .extent = ctx->swapchain->extent, + .view = ctx->swapchain->imageViews->a[0], + .format = ctx->swapchain->format, + }; item = qfv_load_renderpass (ctx, rp, name); rp->renderpass = QFV_ParseRenderPass (ctx, item, rp->renderpassDef); QFV_AddHandle (tab, path, (uint64_t) rp->renderpass); From eb4d5668011bb26443add0ed8582291544c10c75 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 3 Apr 2022 11:11:28 +0900 Subject: [PATCH 10/77] [vkparse] Add support for inheriting objects It simply parses the referenced plist dictionary (via @inherit = plist.path;) into the current data block, then allows the data to be overwritten by the current plist dictionary. This may be a bit iffy for any allocated resources, so some care must be taken, but it seems to work nicely. --- libs/video/renderer/vulkan/vkgen/vkstruct.r | 3 +++ libs/video/renderer/vulkan/vkparse.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 500659bc0..cd580849b 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -130,6 +130,9 @@ [field_def writeParseData]; } fprintf (output_file, "static plfield_t %s_fields[] = {\n", [self outname]); + fprintf (output_file, + "\t{\"@inherit\", 0, QFString, parse_inherit, &%s_fields},\n", + [self outname]); for (int i = [field_defs count]; i-- > 0; ) { FieldDef *field_def = [field_defs objectAtIndex:i]; [field_def writeField]; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 97fdd813d..e6c084672 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -376,6 +376,24 @@ parse_custom (const plfield_t *field, const plitem_t *item, return custom->parse (item, offsets, messages, context); } +static int +parse_inherit (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + exprctx_t ectx = *((parsectx_t *)context)->ectx; + plitem_t *inheritItem = 0; + exprval_t result = { &cexpr_plitem, &inheritItem }; + ectx.result = &result; + const char *inheritstr = PL_String (item); + Sys_MaskPrintf (SYS_vulkan_parse, "parse_inherit: %s\n", inheritstr); + int ret = !cexpr_eval_string (inheritstr, &ectx); + if (ret) { + ret = PL_ParseStruct (field->data, inheritItem, data, messages, + context); + } + return ret; +} + static int parse_RGBA (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context) From 39e7c4a9b2daff1756697db81f11c4bbdc7efb94 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 3 Apr 2022 11:47:53 +0900 Subject: [PATCH 11/77] [vulkan] Use a template for the deferred image views That certainly makes it nicer to work with large sets, and shows one way to be careful with allocated resources: don't allocate them in the inherited data and use a template that needs a few things filled in to be valid. Also, it seems that overriding values in sub-structures "just works" :) --- libs/video/renderer/vulkan/deferred.plist | 102 +++++----------------- 1 file changed, 21 insertions(+), 81 deletions(-) diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index c5ce13c0f..ad1d7df68 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -106,118 +106,58 @@ initialLayout = undefined; }; }; + flat_color_view_template = { + viewType = VK_IMAGE_VIEW_TYPE_2D; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; imageViews = { depth = { + @inherit = $properties.flat_color_view_template; image = depth; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.depth.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; subresourceRange = { aspectMask = depth; - levelCount = 1; - layerCount = 1; }; }; color = { + @inherit = $properties.flat_color_view_template; image = color; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.color.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; - subresourceRange = { - aspectMask = color; - levelCount = 1; - layerCount = 1; - }; }; emission = { + @inherit = $properties.flat_color_view_template; image = emission; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.emission.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; - subresourceRange = { - aspectMask = color; - levelCount = 1; - layerCount = 1; - }; }; normal = { + @inherit = $properties.flat_color_view_template; image = normal; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.normal.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; - subresourceRange = { - aspectMask = color; - levelCount = 1; - layerCount = 1; - }; }; position = { + @inherit = $properties.flat_color_view_template; image = position; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.position.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; - subresourceRange = { - aspectMask = color; - levelCount = 1; - layerCount = 1; - }; }; opaque = { + @inherit = $properties.flat_color_view_template; image = opaque; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.opaque.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; - subresourceRange = { - aspectMask = color; - levelCount = 1; - layerCount = 1; - }; }; translucent = { + @inherit = $properties.flat_color_view_template; image = translucent; - viewType = VK_IMAGE_VIEW_TYPE_2D; format = $properties.images.translucent.format; - components = { - r = identity; - g = identity; - b = identity; - a = identity; - }; - subresourceRange = { - aspectMask = color; - levelCount = 1; - layerCount = 1; - }; }; }; framebuffer = { From d3d081ea0a9294fb588abbad20fdc730469c8768 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 3 Apr 2022 12:02:13 +0900 Subject: [PATCH 12/77] [vulkan] Switch deferred opaque attachment to f16 rgb While looking at the deferred attachment images with using a template in mind, I noticed that the opaque attachment was using 8-bit color. The problem is, it's meant to be HDRI with the compose pass crunching it down to LDRI. Switching to 16-bit float does seem to have made a subtle difference (hey, it's still quake data, not much HDRI in there). --- libs/video/renderer/vulkan/deferred.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index ad1d7df68..e70a1bc27 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -77,7 +77,7 @@ }; opaque = { imageType = `2d; - format = r8g8b8a8_unorm; + format = r16g16b16a16_sfloat; samples = 1; extent = { width = $output.extent.width; From c8e299ca58c6cdb3c1a5a53e040b1e40478fdd16 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 3 Apr 2022 12:25:04 +0900 Subject: [PATCH 13/77] [vulkan] Use a template for the deferred attachment images It's certainly much easier to read and see what's different between the attachment. --- libs/video/renderer/vulkan/deferred.plist | 104 +++++----------------- 1 file changed, 21 insertions(+), 83 deletions(-) diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index e70a1bc27..74c3e7743 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -1,109 +1,47 @@ { + flat_color_image_template = { + imageType = `2d; + samples = 1; + extent = { + width = $output.extent.width; + height = $output.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; images = { depth = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = x8_d24_unorm_pack32; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; usage = depth_stencil_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; color = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = r8g8b8a8_unorm; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; - usage = color_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; emission = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = r16g16b16a16_sfloat; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; - usage = color_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; normal = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = r16g16b16a16_sfloat; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; - usage = color_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; position = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = r32g32b32a32_sfloat; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; - usage = color_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; opaque = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = r16g16b16a16_sfloat; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; - usage = color_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; translucent = { - imageType = `2d; + @inherit = $properties.flat_color_image_template; format = r8g8b8a8_unorm; - samples = 1; - extent = { - width = $output.extent.width; - height = $output.extent.height; - depth = 1; - }; - mipLevels = 1; - arrayLayers = 1; - tiling = optimal; - usage = color_attachment|input_attachment|transient_attachment; - initialLayout = undefined; }; }; flat_color_view_template = { From f66df59c43f5c31d3130785fe264331c346236a0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 3 Apr 2022 13:15:30 +0900 Subject: [PATCH 14/77] [vulkan] Use a template for the attachment desciptions --- libs/video/renderer/vulkan/deferred.plist | 65 ++++++----------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index 74c3e7743..f846b1799 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -116,86 +116,55 @@ { color = "[0, 0, 0, 0]"; }, // translucent { color = "[0, 0, 0, 1]"; }, // output ); + attachment_template = { + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }; renderpass = { attachments = ( { + @inherit = $properties.attachment_template; format = $properties.images.depth.format; - samples = 1; loadOp = clear; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; finalLayout = depth_stencil_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $properties.images.color.format; - samples = 1; loadOp = clear; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; - finalLayout = color_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $properties.images.emission.format; - samples = 1; loadOp = clear; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; - finalLayout = color_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $properties.images.normal.format; - samples = 1; - loadOp = dont_care; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; - finalLayout = color_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $properties.images.position.format; - samples = 1; - loadOp = dont_care; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; - finalLayout = color_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $properties.images.opaque.format; - samples = 1; - loadOp = dont_care; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; - finalLayout = color_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $properties.images.translucent.format; - samples = 1; loadOp = clear; - storeOp = dont_care; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; - finalLayout = color_attachment_optimal; }, { + @inherit = $properties.attachment_template; format = $output.format; - samples = 1; loadOp = clear; storeOp = store; - stencilLoadOp = dont_care; - stencilStoreOp = dont_care; - initialLayout = undefined; finalLayout = present_src_khr; }, ); From e40f3f4f932a2b2c4f16f53a20a84b97f3a3ad2c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Apr 2022 15:38:27 +0900 Subject: [PATCH 15/77] [model] Make alias skin loading a batch operation Really, this won't make all that much difference because alias models with more than one skin are quite rare, and those with animated skin groups are even rarer. However, for those models that do have more than one skin, it will allow for reduced allocation overheads, and when supported (glsl, vulkan, maybe gl), loading all the skins into an array texture (since all skins are the same size, though external skins may vary), but that's not implemented yet, this just wraps the old one skin at a time code. --- include/QF/Vulkan/qf_alias.h | 6 ++---- include/QF/plugin/vid_render.h | 4 +--- include/mod_internal.h | 21 ++++++++++++--------- libs/models/alias/gl_model_alias.c | 16 +++++++++++++++- libs/models/alias/glsl_model_alias.c | 16 +++++++++++++++- libs/models/alias/model_alias.c | 25 ++++++++++++++++++++----- libs/models/alias/sw_model_alias.c | 16 +++++++++++++++- libs/models/alias/vulkan_model_alias.c | 19 ++++++++++++++++++- libs/video/renderer/vid_render_gl.c | 2 +- libs/video/renderer/vid_render_glsl.c | 2 +- libs/video/renderer/vid_render_sw.c | 2 +- libs/video/renderer/vid_render_vulkan.c | 11 ++++------- 12 files changed, 105 insertions(+), 35 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 08ca86e94..24f8a6944 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -94,10 +94,8 @@ struct qfv_renderframe_s; struct entity_s; struct mod_alias_ctx_s; -void *Vulkan_Mod_LoadSkin (struct mod_alias_ctx_s *alias_ctx, byte *skin, - int skinsize, int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc, - struct vulkan_ctx_s *ctx); +void Vulkan_Mod_LoadAllSkins (struct mod_alias_ctx_s *alias_ctx, + struct vulkan_ctx_s *ctx); void Vulkan_Mod_FinalizeAliasModel (struct mod_alias_ctx_s *alias_ctx, struct vulkan_ctx_s *ctx); void Vulkan_Mod_LoadExternalSkins (struct mod_alias_ctx_s *alias_ctx, diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 19ed1e394..f63e6b7db 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -58,9 +58,7 @@ typedef struct vid_model_funcs_s { void (*Mod_LoadSpriteModel) (model_t *mod, void *buffer); void (*Mod_MakeAliasModelDisplayLists) (struct mod_alias_ctx_s *alias_ctx, void *_m, int _s, int extra); - void *(*Mod_LoadSkin) (struct mod_alias_ctx_s *alias_ctx, byte *skin, - int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); + void (*Mod_LoadAllSkins) (struct mod_alias_ctx_s *alias_ctx); void (*Mod_FinalizeAliasModel) (struct mod_alias_ctx_s *alias_ctx); void (*Mod_LoadExternalSkins) (struct mod_alias_ctx_s *alias_ctx); void (*Mod_IQMFinish) (model_t *mod); diff --git a/include/mod_internal.h b/include/mod_internal.h index b54496dc4..af7581266 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -7,9 +7,17 @@ #include "QF/skin.h" #include "QF/plugin/vid_render.h" +typedef struct mod_alias_skin_s { + int skin_num; + int group_num; // -1 if not in an animated group + byte *texels; + maliasskindesc_t *skindesc; +} mod_alias_skin_t; + typedef struct stvertset_s DARRAY_TYPE (stvert_t) stvertset_t; typedef struct mtriangleset_s DARRAY_TYPE (mtriangle_t) mtriangleset_t; typedef struct trivertxset_s DARRAY_TYPE (trivertx_t *) trivertxset_t; +typedef struct askinset_s DARRAY_TYPE (mod_alias_skin_t) askinset_t; typedef struct mod_alias_ctx_s { aliashdr_t *header; @@ -17,6 +25,7 @@ typedef struct mod_alias_ctx_s { stvertset_t stverts; mtriangleset_t triangles; trivertxset_t poseverts; + askinset_t skins; int aliasbboxmins[3]; int aliasbboxmaxs[3]; } mod_alias_ctx_t; @@ -49,27 +58,21 @@ extern vid_model_funcs_t *m_funcs; void gl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, - int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc); +void gl_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx); void gl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx); void gl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx); void gl_Mod_IQMFinish (model_t *mod); void glsl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, - int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc); +void glsl_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx); void glsl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx); void glsl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx); void glsl_Mod_IQMFinish (model_t *mod); void sw_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, - int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc); +void sw_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx); void sw_Mod_IQMFinish (model_t *mod); void gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp); diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index 85d91c3b2..a3e5047aa 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -52,7 +52,7 @@ #include "compat.h" -void * +static void * gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) @@ -103,6 +103,20 @@ gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, return skin + skinsize; } +void +gl_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) +{ + aliashdr_t *header = alias_ctx->header; + int skinsize = header->mdl.skinwidth * header->mdl.skinheight; + + for (size_t i = 0; i < alias_ctx->skins.size; i++) { + __auto_type skin = alias_ctx->skins.a + i; + gl_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, + skin->skin_num, skin->group_num, + skin->group_num != -1, skin->skindesc); + } +} + void gl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index c48500ad7..f5e74b62f 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -90,7 +90,7 @@ glsl_alias_clear (model_t *m, void *data) } } -void * +static void * glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) @@ -114,6 +114,20 @@ glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, return skin + skinsize; } +void +glsl_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) +{ + aliashdr_t *header = alias_ctx->header; + int skinsize = header->mdl.skinwidth * header->mdl.skinheight; + + for (size_t i = 0; i < alias_ctx->skins.size; i++) { + __auto_type skin = alias_ctx->skins.a + i; + glsl_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, + skin->skin_num, skin->group_num, + skin->group_num != -1, skin->skindesc); + } +} + void glsl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index aa1186b98..4e1832bd2 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -75,8 +75,14 @@ Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, int numskins, pskindesc[snum].type = pskintype->type; if (pskintype->type == ALIAS_SKIN_SINGLE) { skin = (byte *) (pskintype + 1); - skin = m_funcs->Mod_LoadSkin (alias_ctx, skin, skinsize, snum, 0, - false, &pskindesc[snum]); + mod_alias_skin_t askin = { + .skin_num = snum, + .group_num = -1, + .texels = skin, + .skindesc = &pskindesc[snum], + }; + skin += skinsize; + DARRAY_APPEND (&alias_ctx->skins, askin); } else { pskintype++; pinskingroup = (daliasskingroup_t *) pskintype; @@ -107,13 +113,20 @@ Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, int numskins, for (gnum = 0; gnum < groupskins; gnum++) { paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE; - skin = mod_funcs->Mod_LoadSkin (alias_ctx, skin, skinsize, - snum, gnum, true, - &paliasskingroup->skindescs[gnum]); + skin = (byte *) (pskintype + 1); + mod_alias_skin_t askin = { + .skin_num = snum, + .group_num = gnum, + .texels = skin, + .skindesc = &paliasskingroup->skindescs[gnum], + }; + skin += skinsize; + DARRAY_APPEND (&alias_ctx->skins, askin); } } pskintype = (daliasskintype_t *) skin; } + mod_funcs->Mod_LoadAllSkins (alias_ctx); return pskintype; } @@ -232,6 +245,7 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) DARRAY_INIT (&alias_ctx.poseverts, 256); DARRAY_INIT (&alias_ctx.stverts, 256); DARRAY_INIT (&alias_ctx.triangles, 256); + DARRAY_INIT (&alias_ctx.skins, 256); if (LittleLong (* (unsigned int *) buffer) == HEADER_MDL16) extra = 1; // extra precision bytes @@ -392,4 +406,5 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) DARRAY_CLEAR (&alias_ctx.poseverts); DARRAY_CLEAR (&alias_ctx.stverts); DARRAY_CLEAR (&alias_ctx.triangles); + DARRAY_CLEAR (&alias_ctx.skins); } diff --git a/libs/models/alias/sw_model_alias.c b/libs/models/alias/sw_model_alias.c index 62a559332..cd67e1f3f 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -49,7 +49,7 @@ // an animating sequence of poses -void * +static void * sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) @@ -64,6 +64,20 @@ sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, return skin + skinsize; } +void +sw_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) +{ + aliashdr_t *header = alias_ctx->header; + int skinsize = header->mdl.skinwidth * header->mdl.skinheight; + + for (size_t i = 0; i < alias_ctx->skins.size; i++) { + __auto_type skin = alias_ctx->skins.a + i; + sw_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, + skin->skin_num, skin->group_num, + skin->group_num != -1, skin->skindesc); + } +} + static void process_frame (mod_alias_ctx_t *alias_ctx, maliasframedesc_t *frame, int posenum, int extra) diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 0bda057bb..89cadd84f 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -111,7 +111,7 @@ vulkan_alias_clear (model_t *m, void *data) } } -void * +static void * Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc, vulkan_ctx_t *ctx) @@ -228,6 +228,20 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, return skinpix + skinsize; } +void +Vulkan_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) +{ + aliashdr_t *header = alias_ctx->header; + int skinsize = header->mdl.skinwidth * header->mdl.skinheight; + + for (size_t i = 0; i < alias_ctx->skins.size; i++) { + __auto_type skin = alias_ctx->skins.a + i; + Vulkan_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, + skin->skin_num, skin->group_num, + skin->group_num != -1, skin->skindesc, ctx); + } +} + void Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) { @@ -401,6 +415,9 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, for (i = 0; i < numtris; i++) { for (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 + // the vertex is the original or the duplicate if (alias_ctx->stverts.a[vind].onseam && !alias_ctx->triangles.a[i].facesfront) { vind = indexmap[vind]; diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 0d5f5b640..1dc1d337b 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -163,7 +163,7 @@ static vid_model_funcs_t model_funcs = { Mod_LoadSpriteModel, gl_Mod_MakeAliasModelDisplayLists, - gl_Mod_LoadSkin, + gl_Mod_LoadAllSkins, gl_Mod_FinalizeAliasModel, gl_Mod_LoadExternalSkins, gl_Mod_IQMFinish, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 5c93e36b1..7297739f7 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -74,7 +74,7 @@ static vid_model_funcs_t model_funcs = { Mod_LoadSpriteModel, glsl_Mod_MakeAliasModelDisplayLists, - glsl_Mod_LoadSkin, + glsl_Mod_LoadAllSkins, glsl_Mod_FinalizeAliasModel, glsl_Mod_LoadExternalSkins, glsl_Mod_IQMFinish, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 14e09d3d4..727293ee5 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -83,7 +83,7 @@ static vid_model_funcs_t model_funcs = { Mod_LoadSpriteModel, sw_Mod_MakeAliasModelDisplayLists, - sw_Mod_LoadSkin, + sw_Mod_LoadAllSkins, 0, 0, sw_Mod_IQMFinish, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 94ffcc987..3f4fb4b38 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -540,13 +540,10 @@ vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, vulkan_ctx); } -static void * -vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, - int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc) +static void +vulkan_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) { - return Vulkan_Mod_LoadSkin (alias_ctx, skin, skinsize, snum, gnum, group, - skindesc, vulkan_ctx); + Vulkan_Mod_LoadAllSkins (alias_ctx, vulkan_ctx); } static void @@ -638,7 +635,7 @@ static vid_model_funcs_t model_funcs = { Mod_LoadSpriteModel, vulkan_Mod_MakeAliasModelDisplayLists, - vulkan_Mod_LoadSkin, + vulkan_Mod_LoadAllSkins, vulkan_Mod_FinalizeAliasModel, vulkan_Mod_LoadExternalSkins, vulkan_Mod_IQMFinish, From b011f9101866491c78de28ff6fa9eea4ce8614c0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Apr 2022 17:47:21 +0900 Subject: [PATCH 16/77] [model] Clean up alias skin loading a little The improved allocation overheads have been implemented for gl and sw, and glsl no longer uses malloc. Using array textures will have to wait as the current texture loading code doesn't support them. --- libs/models/alias/gl_model_alias.c | 40 +++++++++++++--------------- libs/models/alias/glsl_model_alias.c | 31 +++++++++------------ libs/models/alias/sw_model_alias.c | 26 +++++------------- 3 files changed, 38 insertions(+), 59 deletions(-) diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index a3e5047aa..5abc7e4d5 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -52,55 +52,47 @@ #include "compat.h" -static void * -gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, - int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc) +static void +gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *texels, + int snum, int gnum, maliasskindesc_t *skindesc) { aliashdr_t *header = alias_ctx->header; - byte *pskin; char modname[MAX_QPATH + 4]; int fb_texnum = 0, texnum = 0; dstring_t *name = dstring_new (); - pskin = Hunk_AllocName (0, skinsize, alias_ctx->mod->name); - skindesc->skin = (byte *) pskin - (byte *) header; - - memcpy (pskin, skin, skinsize); - - Mod_FloodFillSkin (pskin, header->mdl.skinwidth, header->mdl.skinheight); + Mod_FloodFillSkin (texels, header->mdl.skinwidth, header->mdl.skinheight); // save 8 bit texels for the player model to remap // FIXME remove model restriction if (strequal (alias_ctx->mod->path, "progs/player.mdl")) gl_Skin_SetPlayerSkin (header->mdl.skinwidth, header->mdl.skinheight, - pskin); + texels); QFS_StripExtension (alias_ctx->mod->path, modname); if (!alias_ctx->mod->fullbright) { - if (group) { + if (gnum != -1) { dsprintf (name, "fb_%s_%i_%i", modname, snum, gnum); } else { dsprintf (name, "fb_%s_%i", modname, snum); } - fb_texnum = Mod_Fullbright (pskin, header->mdl.skinwidth, + fb_texnum = Mod_Fullbright (texels, header->mdl.skinwidth, header->mdl.skinheight, name->str); Sys_MaskPrintf (SYS_glt, "%s %d\n", name->str, fb_texnum); } - if (group) { + if (gnum != -1) { dsprintf (name, "%s_%i_%i", modname, snum, gnum); } else { dsprintf (name, "%s_%i", modname, snum); } texnum = GL_LoadTexture (name->str, header->mdl.skinwidth, - header->mdl.skinheight, pskin, true, false, 1); + header->mdl.skinheight, texels, true, false, 1); Sys_MaskPrintf (SYS_glt, "%s %d\n", name->str, texnum); skindesc->texnum = texnum; skindesc->fb_texnum = fb_texnum; alias_ctx->mod->hasfullbrights = fb_texnum; dstring_delete (name); // alpha param was true for non group skins - return skin + skinsize; } void @@ -108,12 +100,18 @@ gl_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) { aliashdr_t *header = alias_ctx->header; int skinsize = header->mdl.skinwidth * header->mdl.skinheight; + int num_skins = alias_ctx->skins.size; + byte *texel_block = Hunk_AllocName (0, skinsize * num_skins, + alias_ctx->mod->name); - for (size_t i = 0; i < alias_ctx->skins.size; i++) { + for (int i = 0; i < num_skins; i++) { __auto_type skin = alias_ctx->skins.a + i; - gl_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, - skin->skin_num, skin->group_num, - skin->group_num != -1, skin->skindesc); + byte *texels = texel_block + i * skinsize; + + skin->skindesc->skin = texels - (byte *) header; + memcpy (texels, skin->texels, skinsize); + gl_Mod_LoadSkin (alias_ctx, texels, skin->skin_num, skin->group_num, + skin->skindesc); } } diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index f5e74b62f..4e04b419d 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -48,6 +48,7 @@ #include "QF/GLSL/qf_textures.h" #include "mod_internal.h" +#include "qfalloca.h" #include "r_shared.h" static vec3_t vertex_normals[NUMVERTEXNORMALS] = { @@ -90,41 +91,33 @@ glsl_alias_clear (model_t *m, void *data) } } -static void * -glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, - int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc) +static void +glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *texels, + int snum, int gnum, maliasskindesc_t *skindesc) { aliashdr_t *header = alias_ctx->header; - byte *tskin; + int w = header->mdl.skinwidth; + int h = header->mdl.skinheight; + size_t skinsize = w * h; + byte *tskin = alloca (skinsize); const char *name; - int w, h; - w = header->mdl.skinwidth; - h = header->mdl.skinheight; - tskin = malloc (skinsize); - memcpy (tskin, skin, skinsize); + memcpy (tskin, texels, skinsize); Mod_FloodFillSkin (tskin, w, h); - if (group) + if (gnum != -1) name = va (0, "%s_%i_%i", alias_ctx->mod->path, snum, gnum); else name = va (0, "%s_%i", alias_ctx->mod->path, snum); skindesc->texnum = GLSL_LoadQuakeTexture (name, w, h, tskin); - free (tskin); - return skin + skinsize; } void glsl_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) { - aliashdr_t *header = alias_ctx->header; - int skinsize = header->mdl.skinwidth * header->mdl.skinheight; - for (size_t i = 0; i < alias_ctx->skins.size; i++) { __auto_type skin = alias_ctx->skins.a + i; - glsl_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, - skin->skin_num, skin->group_num, - skin->group_num != -1, skin->skindesc); + glsl_Mod_LoadSkin (alias_ctx, skin->texels, + skin->skin_num, skin->group_num, skin->skindesc); } } diff --git a/libs/models/alias/sw_model_alias.c b/libs/models/alias/sw_model_alias.c index cd67e1f3f..797ec38de 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -48,33 +48,21 @@ // a pose is a single set of vertexes. a frame may be // an animating sequence of poses - -static void * -sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, - int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc) -{ - byte *pskin; - - pskin = Hunk_AllocName (0, skinsize, alias_ctx->mod->name); - skindesc->skin = (byte *) pskin - (byte *) alias_ctx->header; - - memcpy (pskin, skin, skinsize); - - return skin + skinsize; -} - void sw_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx) { aliashdr_t *header = alias_ctx->header; int skinsize = header->mdl.skinwidth * header->mdl.skinheight; + int num_skins = alias_ctx->skins.size; + byte *texel_block = Hunk_AllocName (0, skinsize * num_skins, + alias_ctx->mod->name); for (size_t i = 0; i < alias_ctx->skins.size; i++) { __auto_type skin = alias_ctx->skins.a + i; - sw_Mod_LoadSkin (alias_ctx, skin->texels, skinsize, - skin->skin_num, skin->group_num, - skin->group_num != -1, skin->skindesc); + byte *texels = texel_block + i * skinsize; + + skin->skindesc->skin = texels - (byte *) header; + memcpy (texels, skin->texels, skinsize); } } From 2798b5fd587bfaaf20e09edeb61685e56f2cfc1c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 6 Apr 2022 14:40:40 +0900 Subject: [PATCH 17/77] [vulkan] Use cached memory for the bsp index buffer Since it is updated every frame, it needs to be as fast as possible for the cpu code. This seems to make a difference of about 10us (~130 -> ~120) when testing in marcher. Not a huge change, but the timing calculation was wrapped around the entire base world pass, so there was a fair bit of overhead from bsp traversal etc. --- libs/video/renderer/vulkan/vulkan_bsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a6047f57b..464af0280 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -522,7 +522,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) "buffer:bsp:index"); bctx->index_memory = QFV_AllocBufferMemory (device, bctx->index_buffer, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, index_buffer_size, 0); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, bctx->index_memory, "memory:bsp:index"); From 3f575ab02587e839f3c90b42b13c5a6de81428d8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 6 Apr 2022 18:36:07 +0900 Subject: [PATCH 18/77] [win] Update for moved vulkan viewport I forgot to do a windows test build. --- libs/video/targets/vid_win_vulkan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/video/targets/vid_win_vulkan.c b/libs/video/targets/vid_win_vulkan.c index 240fa2355..c67826ccb 100644 --- a/libs/video/targets/vid_win_vulkan.c +++ b/libs/video/targets/vid_win_vulkan.c @@ -155,10 +155,8 @@ win_vulkan_create_surface (vulkan_ctx_t *ctx) .hwnd = pres->window, }; - int width = viddef.width; - int height = viddef.height; - ctx->viewport = (VkViewport) { 0, 0, width, height, 0, 1 }; - ctx->scissor = (VkRect2D) { {0, 0}, {width, height} }; + ctx->window_width = viddef.width; + ctx->window_height = viddef.height; if (pres->vkCreateWin32SurfaceKHR (inst, &createInfo, 0, &surface) != VK_SUCCESS) { From 8f56f28ad7c2442c82483b36c2e793b45dcde8ae Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 6 Apr 2022 18:46:28 +0900 Subject: [PATCH 19/77] [net] Use designated initializers for drivers Not that I expect anything to change any time soon, but nice to have the initializers explicitly named. --- libs/net/nm/net_bsd.c | 100 +++++++++++++++++++++--------------------- libs/net/nm/net_win.c | 100 +++++++++++++++++++++--------------------- 2 files changed, 102 insertions(+), 98 deletions(-) diff --git a/libs/net/nm/net_bsd.c b/libs/net/nm/net_bsd.c index 008a0b58a..3e49f31e8 100644 --- a/libs/net/nm/net_bsd.c +++ b/libs/net/nm/net_bsd.c @@ -34,36 +34,37 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] = { { - "Loopback", - false, - Loop_Init, - Loop_Listen, - Loop_SearchForHosts, - Loop_Connect, - Loop_CheckNewConnections, - Loop_GetMessage, - Loop_SendMessage, - Loop_SendUnreliableMessage, - Loop_CanSendMessage, - Loop_CanSendUnreliableMessage, - Loop_Close, - Loop_Shutdown} - , + .name = "Loopback", + .initialized = false, + .Init = Loop_Init, + .Listen = Loop_Listen, + .SearchForHosts = Loop_SearchForHosts, + .Connect = Loop_Connect, + .CheckNewConnections = Loop_CheckNewConnections, + .QGetMessage = Loop_GetMessage, + .QSendMessage = Loop_SendMessage, + .SendUnreliableMessage = Loop_SendUnreliableMessage, + .CanSendMessage = Loop_CanSendMessage, + .CanSendUnreliableMessage = Loop_CanSendUnreliableMessage, + .Close = Loop_Close, + .Shutdown = Loop_Shutdown, + }, { - "Datagram", - false, - Datagram_Init, - Datagram_Listen, - Datagram_SearchForHosts, - Datagram_Connect, - Datagram_CheckNewConnections, - Datagram_GetMessage, - Datagram_SendMessage, - Datagram_SendUnreliableMessage, - Datagram_CanSendMessage, - Datagram_CanSendUnreliableMessage, - Datagram_Close, - Datagram_Shutdown} + .name = "Datagram", + .initialized = false, + .Init = Datagram_Init, + .Listen = Datagram_Listen, + .SearchForHosts = Datagram_SearchForHosts, + .Connect = Datagram_Connect, + .CheckNewConnections = Datagram_CheckNewConnections, + .QGetMessage = Datagram_GetMessage, + .QSendMessage = Datagram_SendMessage, + .SendUnreliableMessage = Datagram_SendUnreliableMessage, + .CanSendMessage = Datagram_CanSendMessage, + .CanSendUnreliableMessage = Datagram_CanSendUnreliableMessage, + .Close = Datagram_Close, + .Shutdown = Datagram_Shutdown, + }, }; int net_numdrivers = 2; @@ -72,26 +73,27 @@ int net_numdrivers = 2; net_landriver_t net_landrivers[MAX_NET_DRIVERS] = { { - "UDP", - false, - 0, - UDP_Init, - UDP_Shutdown, - UDP_Listen, - UDP_OpenSocket, - UDP_CloseSocket, - UDP_Connect, - UDP_CheckNewConnections, - UDP_Read, - UDP_Write, - UDP_Broadcast, - UDP_AddrToString, - UDP_GetSocketAddr, - UDP_GetNameFromAddr, - UDP_GetAddrFromName, - UDP_AddrCompare, - UDP_GetSocketPort, - UDP_SetSocketPort} + .name = "UDP", + .initialized = false, + .controlSock = 0, + .Init = UDP_Init, + .Shutdown = UDP_Shutdown, + .Listen = UDP_Listen, + .OpenSocket = UDP_OpenSocket, + .CloseSocket = UDP_CloseSocket, + .Connect = UDP_Connect, + .CheckNewConnections = UDP_CheckNewConnections, + .Read = UDP_Read, + .Write = UDP_Write, + .Broadcast = UDP_Broadcast, + .AddrToString = UDP_AddrToString, + .GetSocketAddr = UDP_GetSocketAddr, + .GetNameFromAddr = UDP_GetNameFromAddr, + .GetAddrFromName = UDP_GetAddrFromName, + .AddrCompare = UDP_AddrCompare, + .GetSocketPort = UDP_GetSocketPort, + .SetSocketPort = UDP_SetSocketPort, + }, }; int net_numlandrivers = 1; diff --git a/libs/net/nm/net_win.c b/libs/net/nm/net_win.c index 0dcbd27e6..f343d907a 100644 --- a/libs/net/nm/net_win.c +++ b/libs/net/nm/net_win.c @@ -33,36 +33,37 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] = { { - "Loopback", - false, - Loop_Init, - Loop_Listen, - Loop_SearchForHosts, - Loop_Connect, - Loop_CheckNewConnections, - Loop_GetMessage, - Loop_SendMessage, - Loop_SendUnreliableMessage, - Loop_CanSendMessage, - Loop_CanSendUnreliableMessage, - Loop_Close, - Loop_Shutdown} - , + .name = "Loopback", + .initialized = false, + .Init = Loop_Init, + .Listen = Loop_Listen, + .SearchForHosts = Loop_SearchForHosts, + .Connect = Loop_Connect, + .CheckNewConnections = Loop_CheckNewConnections, + .QGetMessage = Loop_GetMessage, + .QSendMessage = Loop_SendMessage, + .SendUnreliableMessage = Loop_SendUnreliableMessage, + .CanSendMessage = Loop_CanSendMessage, + .CanSendUnreliableMessage = Loop_CanSendUnreliableMessage, + .Close = Loop_Close, + .Shutdown = Loop_Shutdown, + }, { - "Datagram", - false, - Datagram_Init, - Datagram_Listen, - Datagram_SearchForHosts, - Datagram_Connect, - Datagram_CheckNewConnections, - Datagram_GetMessage, - Datagram_SendMessage, - Datagram_SendUnreliableMessage, - Datagram_CanSendMessage, - Datagram_CanSendUnreliableMessage, - Datagram_Close, - Datagram_Shutdown} + .name = "Datagram", + .initialized = false, + .Init = Datagram_Init, + .Listen = Datagram_Listen, + .SearchForHosts = Datagram_SearchForHosts, + .Connect = Datagram_Connect, + .CheckNewConnections = Datagram_CheckNewConnections, + .QGetMessage = Datagram_GetMessage, + .QSendMessage = Datagram_SendMessage, + .SendUnreliableMessage = Datagram_SendUnreliableMessage, + .CanSendMessage = Datagram_CanSendMessage, + .CanSendUnreliableMessage = Datagram_CanSendUnreliableMessage, + .Close = Datagram_Close, + .Shutdown = Datagram_Shutdown, + }, }; int net_numdrivers = 2; @@ -72,26 +73,27 @@ int net_numdrivers = 2; net_landriver_t net_landrivers[MAX_NET_DRIVERS] = { { - "Winsock TCPIP", - false, - 0, - WINS_Init, - WINS_Shutdown, - WINS_Listen, - WINS_OpenSocket, - WINS_CloseSocket, - WINS_Connect, - WINS_CheckNewConnections, - WINS_Read, - WINS_Write, - WINS_Broadcast, - WINS_AddrToString, - WINS_GetSocketAddr, - WINS_GetNameFromAddr, - WINS_GetAddrFromName, - WINS_AddrCompare, - WINS_GetSocketPort, - WINS_SetSocketPort}, + .name = "Winsock TCPIP", + .initialized = false, + .controlSock = 0, + .Init = WINS_Init, + .Shutdown = WINS_Shutdown, + .Listen = WINS_Listen, + .OpenSocket = WINS_OpenSocket, + .CloseSocket = WINS_CloseSocket, + .Connect = WINS_Connect, + .CheckNewConnections = WINS_CheckNewConnections, + .Read = WINS_Read, + .Write = WINS_Write, + .Broadcast = WINS_Broadcast, + .AddrToString = WINS_AddrToString, + .GetSocketAddr = WINS_GetSocketAddr, + .GetNameFromAddr = WINS_GetNameFromAddr, + .GetAddrFromName = WINS_GetAddrFromName, + .AddrCompare = WINS_AddrCompare, + .GetSocketPort = WINS_GetSocketPort, + .SetSocketPort = WINS_SetSocketPort, + }, }; int net_numlandrivers = 1; From f6541dbe3f8ac99ce272fea69461f409b397b148 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 6 Apr 2022 19:32:55 +0900 Subject: [PATCH 20/77] [net] Remove client references from net_main This is progress towards #23. There are still some references to host_time and host_client (via nq's server.h), and a lot of references to sv and svs, but this is definitely a step in the right direction. --- include/netmain.h | 5 ++++- libs/net/net_main.c | 21 +++++++++++++-------- libs/net/nm/net_dgrm.c | 2 -- libs/net/nm/net_loop.c | 3 +-- libs/net/nm/net_wins.c | 1 - nq/include/client.h | 1 - nq/source/cl_main.c | 4 +--- nq/source/host.c | 22 +++++++++++----------- nq/source/host_cmd.c | 14 +++++++------- nq/source/sv_main.c | 2 +- nq/source/sys_sdl.c | 2 +- nq/source/sys_unix.c | 2 +- nq/source/sys_win.c | 2 +- 13 files changed, 41 insertions(+), 40 deletions(-) diff --git a/include/netmain.h b/include/netmain.h index 0a4587b26..882b7acc9 100644 --- a/include/netmain.h +++ b/include/netmain.h @@ -270,9 +270,11 @@ extern double net_time; extern struct msg_s *net_message; extern unsigned net_activeconnections; +struct cbuf_s; + /** Initialize the networking sub-system. */ -void NET_Init (void); +void NET_Init (struct cbuf_s *cbuf); /** Check for new connections. @@ -447,6 +449,7 @@ typedef struct { extern int net_numdrivers; extern net_driver_t net_drivers[MAX_NET_DRIVERS]; +extern int net_is_dedicated; ///@} diff --git a/libs/net/net_main.c b/libs/net/net_main.c index e534c4156..6ef7e9a0f 100644 --- a/libs/net/net_main.c +++ b/libs/net/net_main.c @@ -47,9 +47,10 @@ #include "netmain.h" #include "net_vcr.h" -#include "../nq/include/host.h" #include "../nq/include/server.h" +int net_is_dedicated = 0; + qsocket_t *net_activeSockets = NULL; qsocket_t *net_freeSockets = NULL; int net_numsockets = 0; @@ -102,6 +103,8 @@ double net_time; static int hostCacheCount = 0; static hostcache_t hostcache[HOSTCACHESIZE]; +static cbuf_t *net_cbuf; + double SetNetTime (void) { @@ -219,10 +222,10 @@ MaxPlayers_f (void) } if ((n == 1) && listening) - Cbuf_AddText (host_cbuf, "listen 0\n"); + Cbuf_AddText (net_cbuf, "listen 0\n"); if ((n > 1) && (!listening)) - Cbuf_AddText (host_cbuf, "listen 1\n"); + Cbuf_AddText (net_cbuf, "listen 1\n"); svs.maxclients = n; if (n == 1) @@ -253,8 +256,8 @@ NET_Port_f (void) if (listening) { // force a change to the new port - Cbuf_AddText (host_cbuf, "listen 0\n"); - Cbuf_AddText (host_cbuf, "listen 1\n"); + Cbuf_AddText (net_cbuf, "listen 0\n"); + Cbuf_AddText (net_cbuf, "listen 1\n"); } } @@ -796,12 +799,14 @@ NET_shutdown (void *data) } void -NET_Init (void) +NET_Init (cbuf_t *cbuf) { int i; int controlSocket; qsocket_t *s; + net_cbuf = cbuf; + Sys_RegisterShutdown (NET_shutdown, 0); if (COM_CheckParm ("-playback")) { @@ -826,10 +831,10 @@ NET_Init (void) } net_hostport = DEFAULTnet_hostport; - if (COM_CheckParm ("-listen") || cls.state == ca_dedicated) + if (COM_CheckParm ("-listen") || net_is_dedicated) listening = true; net_numsockets = svs.maxclientslimit; - if (cls.state != ca_dedicated) + if (!net_is_dedicated) net_numsockets++; SetNetTime (); diff --git a/libs/net/nm/net_dgrm.c b/libs/net/nm/net_dgrm.c index 9aa10ef31..71f74ff4a 100644 --- a/libs/net/nm/net_dgrm.c +++ b/libs/net/nm/net_dgrm.c @@ -46,9 +46,7 @@ #include "netmain.h" -#include "../nq/include/client.h" #include "../nq/include/server.h" -#include "../nq/include/game.h" // This is enables a simple IP banning mechanism #define BAN_TEST diff --git a/libs/net/nm/net_loop.c b/libs/net/nm/net_loop.c index cb1ddb180..ddf61f6f3 100644 --- a/libs/net/nm/net_loop.c +++ b/libs/net/nm/net_loop.c @@ -35,7 +35,6 @@ #include "netmain.h" #include "net_loop.h" -#include "../nq/include/client.h" #include "../nq/include/server.h" qboolean localconnectpending = false; @@ -45,7 +44,7 @@ qsocket_t *loop_server = NULL; __attribute__((pure)) int Loop_Init (void) { - if (cls.state == ca_dedicated) + if (net_is_dedicated) return -1; return 0; } diff --git a/libs/net/nm/net_wins.c b/libs/net/nm/net_wins.c index 6b779bfa5..411c0b838 100644 --- a/libs/net/nm/net_wins.c +++ b/libs/net/nm/net_wins.c @@ -1,4 +1,3 @@ - /* net_wins.c diff --git a/nq/include/client.h b/nq/include/client.h index 3096f6321..4e5c148e8 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -70,7 +70,6 @@ typedef enum { #define MAX_DEMONAME 16 typedef enum { - ca_dedicated, // a dedicated server with no ability to start a client ca_disconnected, // full screen console with no connection ca_connected, // talking to a server ca_active, // everything is in, so frames can be rendered diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 3b63db068..1a489621a 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -306,7 +306,7 @@ CL_Disconnect_f (void) void CL_EstablishConnection (const char *host) { - if (cls.state == ca_dedicated) + if (net_is_dedicated) return; if (cls.demoplayback) @@ -510,8 +510,6 @@ CL_SetState (cactive_t state) r_funcs->R_ClearState (); } switch (state) { - case ca_dedicated: - break; case ca_disconnected: CL_ClearState (); cls.signon = so_none; diff --git a/nq/source/host.c b/nq/source/host.c index d19d30114..86b428c5a 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -157,7 +157,7 @@ Host_EndGame (const char *message, ...) if (sv.active) Host_ShutdownServer (false); - if (cls.state == ca_dedicated) + if (net_is_dedicated) Sys_Error ("Host_EndGame: %s", str->str); // dedicated servers exit if (cls.demonum != -1) @@ -197,7 +197,7 @@ Host_Error (const char *error, ...) if (sv.active) Host_ShutdownServer (false); - if (cls.state == ca_dedicated) + if (net_is_dedicated) Sys_Error ("Host_Error: %s", str->str); // dedicated servers exit Sys_Printf ("Host_Error: %s\n", str->str); @@ -219,17 +219,17 @@ Host_FindMaxClients (void) i = COM_CheckParm ("-dedicated"); if (i) { - cls.state = ca_dedicated; if (i != (com_argc - 1)) { svs.maxclients = atoi (com_argv[i + 1]); } else svs.maxclients = 8; - } else - cls.state = ca_disconnected; + } + cls.state = ca_disconnected; + net_is_dedicated = i; i = COM_CheckParm ("-listen"); if (i) { - if (cls.state == ca_dedicated) + if (net_is_dedicated) Sys_Error ("Only one of -dedicated or -listen can be specified"); if (i != (com_argc - 1)) svs.maxclients = atoi (com_argv[i + 1]); @@ -676,10 +676,10 @@ _Host_Frame (float time) return; } - if (cls.state != ca_dedicated) + if (!net_is_dedicated) IN_ProcessEvents (); - if (cls.state == ca_dedicated) + if (net_is_dedicated) Con_ProcessInput (); GIB_Thread_Execute (); @@ -708,7 +708,7 @@ _Host_Frame (float time) Host_ServerFrame (); } - if (cls.state != ca_dedicated) + if (!net_is_dedicated) Host_ClientFrame (); else host_time += host_frametime; //FIXME is this needed? vcr stuff @@ -920,13 +920,13 @@ Host_Init (void) Host_InitVCR (&host_parms); Host_InitLocal (); - NET_Init (); + NET_Init (host_cbuf); Mod_Init (); SV_Init (); - if (cls.state != ca_dedicated) + if (!net_is_dedicated) CL_Init (host_cbuf); if (con_module) { diff --git a/nq/source/host_cmd.c b/nq/source/host_cmd.c index e58098241..2ad67d3b3 100644 --- a/nq/source/host_cmd.c +++ b/nq/source/host_cmd.c @@ -303,7 +303,7 @@ Host_Map_f (void) if (!sv.active) return; - if (cls.state != ca_dedicated) { + if (!net_is_dedicated) { Cmd_ExecuteString ("connect local", src_command); } } @@ -717,7 +717,7 @@ Host_Loadgame_f (void) for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; - if (cls.state != ca_dedicated) { + if (!net_is_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } @@ -790,7 +790,7 @@ Host_Say (qboolean teamonly) qboolean fromServer = false; if (cmd_source == src_command) { - if (cls.state == ca_dedicated) { + if (net_is_dedicated) { fromServer = true; teamonly = false; } else { @@ -1134,7 +1134,7 @@ Host_Kick_f (void) if (i < svs.maxclients) { if (cmd_source == src_command) - if (cls.state == ca_dedicated) + if (net_is_dedicated) who = "Console"; else who = cl_name->string; @@ -1403,7 +1403,7 @@ Host_Startdemos_f (void) { int i, c; - if (cls.state == ca_dedicated) { + if (net_is_dedicated) { if (!sv.active) Cbuf_AddText (host_cbuf, "map start\n"); return; @@ -1434,7 +1434,7 @@ Host_Startdemos_f (void) static void Host_Demos_f (void) { - if (cls.state == ca_dedicated) + if (net_is_dedicated) return; if (cls.demonum == -1) cls.demonum = 1; @@ -1450,7 +1450,7 @@ Host_Demos_f (void) static void Host_Stopdemo_f (void) { - if (cls.state == ca_dedicated) + if (net_is_dedicated) return; if (!cls.demoplayback) return; diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index 21a18fbfc..57282ea1d 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -1064,7 +1064,7 @@ SV_SendReconnect (void) MSG_WriteString (&msg, "reconnect\n"); NET_SendToAll (&msg, 5.0); - if (cls.state != ca_dedicated) + if (!net_is_dedicated) Cmd_ExecuteString ("reconnect\n", src_command); } diff --git a/nq/source/sys_sdl.c b/nq/source/sys_sdl.c index 76e84b558..68c2e91eb 100644 --- a/nq/source/sys_sdl.c +++ b/nq/source/sys_sdl.c @@ -136,7 +136,7 @@ SDL_main (int argc, char *argv[]) newtime = Sys_DoubleTime (); time = newtime - oldtime; - if (cls.state == ca_dedicated) { // play vcrfiles at max speed + if (net_is_dedicated) { // play vcrfiles at max speed if (time < sys_ticrate->value && (!vcrFile || recording)) { usleep (1); continue; // not time to run a server-only tic yet diff --git a/nq/source/sys_unix.c b/nq/source/sys_unix.c index 20cce79a5..e244b940e 100644 --- a/nq/source/sys_unix.c +++ b/nq/source/sys_unix.c @@ -91,7 +91,7 @@ main (int argc, const char **argv) newtime = Sys_DoubleTime (); time = newtime - oldtime; - if (cls.state == ca_dedicated) { // play vcrfiles at max speed + if (net_is_dedicated) { // play vcrfiles at max speed if (time < sys_ticrate->value && (!vcrFile || recording)) { usleep (1); continue; // not time to run a server-only tic yet diff --git a/nq/source/sys_win.c b/nq/source/sys_win.c index ee040f956..59c61b796 100644 --- a/nq/source/sys_win.c +++ b/nq/source/sys_win.c @@ -228,7 +228,7 @@ WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, newtime = Sys_DoubleTime (); time = newtime - oldtime; - if (cls.state == ca_dedicated) { // play vcrfiles at max speed + if (net_is_dedicated) { // play vcrfiles at max speed if (time < sys_ticrate->value && (!vcrFile || recording)) { Sleep (1); continue; // not time to run a server-only tic yet From 6b81a4b8825f3496e220be071d2b80829a274b9e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 7 Apr 2022 22:30:19 +0900 Subject: [PATCH 21/77] [renderer] Don't try to animate lightstyles that aren't there Prevents a segfault when running the renderer via qwaq-x11. --- libs/video/renderer/r_light.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/video/renderer/r_light.c b/libs/video/renderer/r_light.c index d9a96915e..2f063e9d9 100644 --- a/libs/video/renderer/r_light.c +++ b/libs/video/renderer/r_light.c @@ -126,6 +126,10 @@ R_AnimateLight (void) { int i, j, k; + if (!r_data->lightstyle) { + return; + } + // light animations // 'm' is normal light, 'a' is no light, 'z' is double bright i = (int) (r_data->realtime * 10); From 8d725a1d0a1a02693adbca151bdde4e215b8b822 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 8 Apr 2022 18:27:53 +0900 Subject: [PATCH 22/77] [nq] Clean up Host_Frame_ a little This simplifies the logic around dedicated servers and clients connecting to remote servers. --- nq/source/cl_main.c | 5 ++++ nq/source/host.c | 63 ++++++++++++++++++++------------------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 1a489621a..9a3b00ae1 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -155,6 +155,11 @@ CL_ClearMemory (void) { VID_ClearMemory (); SCR_SetFullscreen (0); + + cls.signon = 0; + __auto_type cam = cl.viewstate.camera_transform; + memset (&cl, 0, sizeof (cl)); + cl.viewstate.camera_transform = cam; } void diff --git a/nq/source/host.c b/nq/source/host.c index 86b428c5a..2e4298007 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -503,12 +503,6 @@ Host_ClearMemory (void) Mod_ClearAll (); if (host_hunklevel) Hunk_FreeToLowMark (0, host_hunklevel); - - cls.signon = 0; - memset (&sv, 0, sizeof (sv)); - __auto_type cam = cl.viewstate.camera_transform; - memset (&cl, 0, sizeof (cl)); - cl.viewstate.camera_transform = cam; } /* @@ -575,19 +569,25 @@ Host_ServerFrame (void) SV_SendClientMessages (); } +static void +write_capture (tex_t *tex, void *data) +{ + QFile *file = QFS_Open (va (0, "%s/qfmv%06d.png", + qfs_gamedir->dir.shots, + cls.demo_capture++), "wb"); + if (file) { + WritePNG (file, tex); + Qclose (file); + } + free (tex); +} + static void Host_ClientFrame (void) { static double time1 = 0, time2 = 0, time3 = 0; int pass1, pass2, pass3; - // if running the server remotely, send intentions now after - // the incoming messages have been read - if (!sv.active) - CL_SendCmd (); - - host_time += host_frametime; - // fetch results from server if (cls.state >= ca_connected) CL_ReadFromServer (); @@ -631,19 +631,10 @@ Host_ClientFrame (void) Sys_Printf ("%3i tot %3i server %3i gfx %3i snd\n", pass1 + pass2 + pass3, pass1, pass2, pass3); } -} -static void -write_capture (tex_t *tex, void *data) -{ - QFile *file = QFS_Open (va (0, "%s/qfmv%06d.png", - qfs_gamedir->dir.shots, - cls.demo_capture++), "wb"); - if (file) { - WritePNG (file, tex); - Qclose (file); + if (cls.demo_capture) { + r_funcs->capture_screen (write_capture, 0); } - free (tex); } /* @@ -675,12 +666,13 @@ _Host_Frame (float time) #endif return; } + host_time += host_frametime; //FIXME is this needed? vcr stuff - if (!net_is_dedicated) - IN_ProcessEvents (); - - if (net_is_dedicated) + if (net_is_dedicated) { Con_ProcessInput (); + } else { + IN_ProcessEvents (); + } GIB_Thread_Execute (); cmd_source = src_command; @@ -703,18 +695,19 @@ _Host_Frame (float time) NET_Poll (); - if (sv.active) { + if (!net_is_dedicated) { + // Whether or not the server is active, if this is not a dedicated + // server, then the client always needs to be able to process input + // and send commands to the server before the server runs a frame. CL_SendCmd (); + } + + if (sv.active) { Host_ServerFrame (); } - if (!net_is_dedicated) + if (!net_is_dedicated) { Host_ClientFrame (); - else - host_time += host_frametime; //FIXME is this needed? vcr stuff - - if (cls.demo_capture) { - r_funcs->capture_screen (write_capture, 0); } host_framecount++; From bffd0605b72737597813b0f96345d5f3f2f4a680 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 8 Apr 2022 18:29:04 +0900 Subject: [PATCH 23/77] [nq] Show sub-millisecond times for serverprofile Integer milliseconds are a little too coarse when the range is 1-3ms. --- nq/source/host.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nq/source/host.c b/nq/source/host.c index 2e4298007..45f23d4a4 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -719,7 +719,8 @@ Host_Frame (float time) { double time1, time2; static double timetotal; - int c, m; + int c; + double m; static int timecount; if (!serverprofile->int_val) { @@ -746,7 +747,7 @@ Host_Frame (float time) c++; } - Sys_Printf ("serverprofile: %2i clients %2i msec\n", c, m); + Sys_Printf ("serverprofile: %2i clients %5.3g msec\n", c, m); } From dcd13e4230c3b680fe76eab07ef640e6d857e018 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 8 Apr 2022 20:07:45 +0900 Subject: [PATCH 24/77] [qw] Fix an extern in a C file Rather worrying finding one. I guess I didn't feel like finding a header for the declaration at time time. --- qw/include/client.h | 2 ++ qw/source/cl_main.c | 1 - qw/source/cl_parse.c | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/qw/include/client.h b/qw/include/client.h index 57b87f514..dbd0f35d0 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -280,6 +280,8 @@ extern struct cvar_s *skin; extern struct cvar_s *cl_fb_players; +extern struct cvar_s *hud_scoreboard_uid; + extern client_state_t cl; extern entity_t *cl_entities[512]; diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index c70a137ef..7b4179907 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -216,7 +216,6 @@ jmp_buf host_abort; char *server_version = NULL; // version of server we connected to -extern cvar_t *hud_scoreboard_uid; static netadr_t cl_cmd_packet_address; static void diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index c7478445d..cd97ec003 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -172,8 +172,6 @@ int cl_h_playerindex, cl_gib1index, cl_gib2index, cl_gib3index; int packet_latency[NET_TIMINGS]; -extern cvar_t *hud_scoreboard_uid; - int CL_CalcNet (void) { From 4d443d31148bfef3f7cef360c9ba702b33016b85 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 8 Apr 2022 20:42:59 +0900 Subject: [PATCH 25/77] [vid] Fix non-utf8 circle-c in fbset Python didn't like reading the files. --- include/fbset.h | 2 +- libs/video/targets/fbset.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fbset.h b/include/fbset.h index 82f2f9bd3..8dc8cbb87 100644 --- a/include/fbset.h +++ b/include/fbset.h @@ -1,7 +1,7 @@ /* * Linux Frame Buffer Device Configuration * - * © Copyright 1995-1998 by Geert Uytterhoeven + * © Copyright 1995-1998 by Geert Uytterhoeven * (Geert.Uytterhoeven@cs.kuleuven.ac.be) * * -------------------------------------------------------------------------- diff --git a/libs/video/targets/fbset.c b/libs/video/targets/fbset.c index 51866326a..c24a5db7a 100644 --- a/libs/video/targets/fbset.c +++ b/libs/video/targets/fbset.c @@ -1,7 +1,7 @@ /* * Linux Frame Buffer Device Configuration * - * © Copyright 1995-1999 by Geert Uytterhoeven + * © Copyright 1995-1999 by Geert Uytterhoeven * (Geert.Uytterhoeven@cs.kuleuven.ac.be) * * -------------------------------------------------------------------------- From e97b96b536f2f04ebf6f3e61e4768b5af1939e07 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 9 Apr 2022 01:06:03 +0900 Subject: [PATCH 26/77] Remove some long dead cvars The declarations were still around, but the creation and code using them was removed long ago. --- include/QF/input.h | 1 - include/d_local.h | 2 -- include/r_cvar.h | 4 ---- include/r_local.h | 1 - include/snd_internal.h | 4 ---- libs/audio/renderer/snd_dma.c | 1 + libs/video/renderer/gl/vid_common_gl.c | 4 ---- nq/include/client.h | 4 ---- qw/include/cl_main.h | 1 - qw/include/client.h | 2 -- qw/source/cl_skin.c | 2 +- 11 files changed, 2 insertions(+), 24 deletions(-) diff --git a/include/QF/input.h b/include/QF/input.h index ade3b97d0..119ad170b 100644 --- a/include/QF/input.h +++ b/include/QF/input.h @@ -129,7 +129,6 @@ void IN_ClearStates (void); extern struct cvar_s *in_grab; extern struct cvar_s *in_amp; extern struct cvar_s *in_pre_amp; -extern struct cvar_s *m_filter; extern struct cvar_s *in_mouse_accel; extern struct cvar_s *in_freelook; extern struct cvar_s *lookstrafe; diff --git a/include/d_local.h b/include/d_local.h index 51a2cd220..7b9cc3fac 100644 --- a/include/d_local.h +++ b/include/d_local.h @@ -63,8 +63,6 @@ typedef struct sspan_s { int u, v, count; } sspan_t; -extern struct cvar_s *d_subdiv16; - extern float scale_for_mip; extern qboolean d_roverwrapped; diff --git a/include/r_cvar.h b/include/r_cvar.h index 5b1090c1d..756c2ef03 100644 --- a/include/r_cvar.h +++ b/include/r_cvar.h @@ -59,9 +59,7 @@ extern struct cvar_s *r_explosionclip; extern struct cvar_s *r_farclip; extern struct cvar_s *r_firecolor; extern struct cvar_s *r_flatlightstyles; -extern struct cvar_s *r_fullbright; extern struct cvar_s *r_graphheight; -extern struct cvar_s *r_lightmap; extern struct cvar_s *r_lightmap_components; extern struct cvar_s *r_maxedges; extern struct cvar_s *r_maxsurfs; @@ -85,8 +83,6 @@ extern struct cvar_s *r_waterripple; extern struct cvar_s *r_waterwarp; extern struct cvar_s *r_zgraph; -extern struct cvar_s *scr_consize; -extern struct cvar_s *scr_conspeed; extern struct cvar_s *scr_fov; extern struct cvar_s *scr_fisheye; extern struct cvar_s *scr_fviews; diff --git a/include/r_local.h b/include/r_local.h index e6a068501..ef0db6963 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -71,7 +71,6 @@ extern struct cvar_s *r_timegraph; extern struct cvar_s *r_graphheight; extern struct cvar_s *r_clearcolor; extern struct cvar_s *r_waterwarp; -extern struct cvar_s *r_fullbright; extern struct cvar_s *r_drawentities; extern struct cvar_s *r_aliasstats; extern struct cvar_s *r_dspeeds; diff --git a/include/snd_internal.h b/include/snd_internal.h index 8d95d0615..078d32cbb 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -229,12 +229,8 @@ struct channel_s { //@} }; -extern struct cvar_s *snd_loadas8bit; extern struct cvar_s *snd_volume; -extern struct cvar_s *snd_interp; -extern struct cvar_s *snd_stereo_phase_separation; - extern snd_render_data_t snd_render_data; #define PAINTBUFFER_SIZE 512 extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2]; diff --git a/libs/audio/renderer/snd_dma.c b/libs/audio/renderer/snd_dma.c index ecf5b2707..010793cae 100644 --- a/libs/audio/renderer/snd_dma.c +++ b/libs/audio/renderer/snd_dma.c @@ -345,6 +345,7 @@ s_init (void) "fix permanently blocked sound"); // FIXME +//extern struct cvar_s *snd_loadas8bit; // if (host_parms.memsize < 0x800000) { // Cvar_Set (snd_loadas8bit, "1"); // Sys_Printf ("loading all sounds as 8bit\n"); diff --git a/libs/video/renderer/gl/vid_common_gl.c b/libs/video/renderer/gl/vid_common_gl.c index d1547d2d9..e0e5f5231 100644 --- a/libs/video/renderer/gl/vid_common_gl.c +++ b/libs/video/renderer/gl/vid_common_gl.c @@ -113,7 +113,6 @@ int gl_tess; int gl_max_lights; cvar_t *gl_anisotropy; -cvar_t *gl_doublebright; cvar_t *gl_fb_bmodels; cvar_t *gl_finish; cvar_t *gl_max_size; @@ -485,9 +484,6 @@ CheckCombineExtensions (void) "doublebright enabled.\n"); } else { gl_combine_capable = false; - Sys_MaskPrintf (SYS_vid, "GL_ARB_texture_env_combine not found. " - "gl_doublebright will have no effect with " - "gl_multitexture on.\n"); } } diff --git a/nq/include/client.h b/nq/include/client.h index 4e5c148e8..de0e7cb02 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -213,13 +213,9 @@ typedef struct client_state_s { extern struct cvar_s *cl_name; extern struct cvar_s *cl_color; -extern struct cvar_s *cl_autofire; - extern struct cvar_s *cl_shownet; extern struct cvar_s *cl_nolerp; -extern struct cvar_s *cl_pitchdriftspeed; - extern struct cvar_s *cl_name; extern struct cvar_s *cl_writecfg; diff --git a/qw/include/cl_main.h b/qw/include/cl_main.h index 640c206cc..61d9d0481 100644 --- a/qw/include/cl_main.h +++ b/qw/include/cl_main.h @@ -52,7 +52,6 @@ void CL_BeginServerConnect(void); #define soundlist_name "soundlist %i %i" -extern struct cvar_s *cl_timeframes; extern struct cvar_s *cl_predict_players; extern struct cvar_s *cl_solid_players; extern struct cvar_s *cl_autoexec; diff --git a/qw/include/client.h b/qw/include/client.h index dbd0f35d0..876bc6cca 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -265,8 +265,6 @@ extern struct cvar_s *cl_netgraph_box; extern struct cvar_s *cl_draw_locs; extern struct cvar_s *cl_shownet; -extern struct cvar_s *cl_pitchdriftspeed; - extern struct cvar_s *cl_name; extern struct cvar_s *cl_model_crcs; diff --git a/qw/source/cl_skin.c b/qw/source/cl_skin.c index 24f2a809d..6ff72805b 100644 --- a/qw/source/cl_skin.c +++ b/qw/source/cl_skin.c @@ -200,7 +200,7 @@ CL_Skin_Init (void) "shirt pants) Note that if only shirt color is given, " "pants will match"); - noskins = Cvar_Get ("noskins", "0", CVAR_ARCHIVE, NULL, //XXX FIXME + noskins = Cvar_Get ("noskins", "0", CVAR_ARCHIVE, NULL, "set to 1 to not download new skins"); skin = Cvar_Get ("skin", "", CVAR_ARCHIVE | CVAR_USERINFO, skin_f, "Players skin"); From 063c0797d60100c7171f942202fd178fe1221e03 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 9 Apr 2022 01:57:14 +0900 Subject: [PATCH 27/77] Fix some inconsistent cvar uses Surprisingly, only two, but they were caught by the different value fields being used, thus the cvar was checked in multiple places. I imagine that's not really all that common, so there may be some inconsistencies between default value and use. --- libs/video/renderer/sw/sw_fisheye.c | 2 +- qw/source/sv_user.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/sw/sw_fisheye.c b/libs/video/renderer/sw/sw_fisheye.c index c1c782e47..83d6c2a15 100644 --- a/libs/video/renderer/sw/sw_fisheye.c +++ b/libs/video/renderer/sw/sw_fisheye.c @@ -128,7 +128,7 @@ R_RenderFisheye (framebuffer_t *cube) { int width = r_refdef.vrect.width; int height = r_refdef.vrect.height; - int fov = scr_ffov->int_val; + float fov = scr_ffov->value; static int pwidth = -1; static int pheight = -1; static int pfov = -1; diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index a9eb02fe4..31dc6c142 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -940,7 +940,7 @@ SV_Say (qboolean team) } // non-team messages should be seen allways, even if not tracking any // player - if (!team && ((host_client->spectator && sv_spectalk->value) + if (!team && ((host_client->spectator && sv_spectalk->int_val) || !host_client->spectator)) { dbuf = SVR_WriteBegin (dem_all, 0, strlen (text->str) + 3); } else { From 32a395a8d57737d0ef0f99b327aba11bb31e5638 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Apr 2022 21:01:41 +0900 Subject: [PATCH 28/77] [dox] Fix up some doxygen issues I found a few doxygen related patches in my git stash and while testing them, found a few doc issues. --- doc/quakeforge.dox.conf.in | 4 +++- include/QF/input.h | 5 +++++ include/QF/input/binding.h | 7 +++++++ include/QF/input/event.h | 7 +++++++ include/QF/input/imt.h | 7 +++++++ include/QF/keys.h | 2 -- include/QF/progs/pr_comp.h | 2 ++ include/QF/sound.h | 3 --- include/snd_internal.h | 6 ++---- 9 files changed, 33 insertions(+), 10 deletions(-) diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 3d22be413..76b963cb4 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -2133,7 +2133,8 @@ SEARCH_INCLUDES = YES INCLUDE_PATH = @TOPSRC@/include \ @TOPSRC@/nq/include \ @TOPSRC@/qw/include \ - @TOPSRC@/qtv/include + @TOPSRC@/qtv/include \ + @TOPSRC@ # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -2152,6 +2153,7 @@ INCLUDE_FILE_PATTERNS = *.h # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = "__attribute__(x)=" \ + IN_DOXYGEN=1 \ VISIBLE= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this diff --git a/include/QF/input.h b/include/QF/input.h index 119ad170b..bb1e8a09c 100644 --- a/include/QF/input.h +++ b/include/QF/input.h @@ -28,6 +28,9 @@ #ifndef __QF_input_h #define __QF_input_h +/** \defgroup input Input Sub-system */ + +///@{ typedef struct in_axisinfo_s { int deviceid; int axis; @@ -135,4 +138,6 @@ extern struct cvar_s *lookstrafe; #endif +///@} + #endif//__QF_input_h diff --git a/include/QF/input/binding.h b/include/QF/input/binding.h index 3570c42e4..02363abe5 100644 --- a/include/QF/input/binding.h +++ b/include/QF/input/binding.h @@ -34,6 +34,11 @@ #include "QF/mathlib.h" #endif +/** \defgroup input_bindings Input Bindings + \ingroup input +*/ +///@{ + /*** Recipe for converting an axis to a floating point value. Absolute axes are converted to the 0..1 range for unbalanced axes, and @@ -366,4 +371,6 @@ void IN_Binding_LoadConfig (struct plitem_s *config); #endif +///@} + #endif//__QF_input_binding_h diff --git a/include/QF/input/event.h b/include/QF/input/event.h index 97902029d..698fd21bb 100644 --- a/include/QF/input/event.h +++ b/include/QF/input/event.h @@ -33,6 +33,11 @@ #include "QF/qtypes.h" +/** \defgroup input_events Input Events + \ingroup input +*/ +///@{ + typedef struct { int xpos, ypos; int xlen, ylen; @@ -122,4 +127,6 @@ void IE_Remove_Handler (int handle); void IE_Set_Focus (int handle); int IE_Get_Focus (void) __attribute__ ((pure)); +///@} + #endif//__QF_in_event_h diff --git a/include/QF/input/imt.h b/include/QF/input/imt.h index e3777e8ea..5f3f8c2d3 100644 --- a/include/QF/input/imt.h +++ b/include/QF/input/imt.h @@ -29,6 +29,11 @@ #ifndef __QF_input_imt_h #define __QF_input_imt_h +/** \defgroup input_imt Input Mapping Tables + \ingroup input +*/ +///@{ + #ifndef __QFCC__ #include "QF/darray.h" @@ -134,4 +139,6 @@ void IMT_LoadConfig (struct plitem_s *config); #endif +///@} + #endif//__QF_input_imt_h diff --git a/include/QF/keys.h b/include/QF/keys.h index caf8f55de..4d0387467 100644 --- a/include/QF/keys.h +++ b/include/QF/keys.h @@ -34,8 +34,6 @@ # include "QF/quakeio.h" #endif -/** \defgroup input Input Sub-system */ - /** \defgroup input_keybinding Key Binding Sub-system \ingroup input */ diff --git a/include/QF/progs/pr_comp.h b/include/QF/progs/pr_comp.h index bc0c1030e..a1051c079 100644 --- a/include/QF/progs/pr_comp.h +++ b/include/QF/progs/pr_comp.h @@ -431,7 +431,9 @@ typedef enum { #define OP_BREAK 0x8000 typedef enum { +#ifndef IN_DOXYGEN #include "QF/progs/pr_opcode.hinc" +#endif } pr_opcode_e; // Used for both branch and comparison, with jump and call being ignored for diff --git a/include/QF/sound.h b/include/QF/sound.h index 7d2227fc4..3e6237962 100644 --- a/include/QF/sound.h +++ b/include/QF/sound.h @@ -133,9 +133,6 @@ void S_StopAllSounds(void); render some sound. \param ear Transform for the position and orientation of the stereo sound pickup. - \param v_forward 3d vector of the client's facing direction - \param v_right 3d vector of the client's rightward direction - \param v_up 3d vector of the client's upward direction \param ambient_sound_level NUM_AMBIENTS bytes indicating current ambient sound levels */ diff --git a/include/snd_internal.h b/include/snd_internal.h index 078d32cbb..59d2f8578 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -353,10 +353,8 @@ void SND_AmbientOn (snd_t *snd); /** Update the sound engine with the client's position and orientation and render some sound. \param snd sound system state - \param origin 3d coords of the client - \param v_forward 3d vector of the client's facing direction - \param v_right 3d vector of the client's rightward direction - \param v_up 3d vector of the client's upward direction + \param ear Transform for the position and orientation of the stereo + sound pickup. \param ambient_sound_level Pointer to 4 bytes indicating the levels at which to play the ambient sounds. */ From b649638400131b4fa8aaefb79313eace2312d6ec Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Apr 2022 11:27:50 +0900 Subject: [PATCH 29/77] [joy] Clean up some redundant cvar flags No need to or CVAR_NONE with other flags. --- libs/video/targets/joy.c | 8 ++++---- libs/video/targets/joy_win.c | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libs/video/targets/joy.c b/libs/video/targets/joy.c index a7a55f6dd..3ff827726 100644 --- a/libs/video/targets/joy.c +++ b/libs/video/targets/joy.c @@ -466,12 +466,12 @@ JOY_Init_Cvars (void) int i; joy_device = Cvar_Get ("joy_device", "/dev/input/js0", - CVAR_NONE | CVAR_ROM, 0, "Joystick device"); - joy_enable = Cvar_Get ("joy_enable", "1", CVAR_NONE | CVAR_ARCHIVE, 0, + CVAR_ROM, 0, "Joystick device"); + joy_enable = Cvar_Get ("joy_enable", "1", CVAR_ARCHIVE, 0, "Joystick enable flag"); - joy_amp = Cvar_Get ("joy_amp", "1", CVAR_NONE | CVAR_ARCHIVE, joyamp_f, + joy_amp = Cvar_Get ("joy_amp", "1", CVAR_ARCHIVE, joyamp_f, "Joystick amplification"); - joy_pre_amp = Cvar_Get ("joy_pre_amp", "0.01", CVAR_NONE | CVAR_ARCHIVE, + joy_pre_amp = Cvar_Get ("joy_pre_amp", "0.01", CVAR_ARCHIVE, joyamp_f, "Joystick pre-amplification"); Cmd_AddCommand ("in_joy", in_joy_f, "Configures the joystick behaviour"); diff --git a/libs/video/targets/joy_win.c b/libs/video/targets/joy_win.c index babd2e270..f42b5022a 100644 --- a/libs/video/targets/joy_win.c +++ b/libs/video/targets/joy_win.c @@ -353,12 +353,11 @@ void JOY_Init_Cvars(void) { // joystick variables - joy_device = Cvar_Get ("joy_device", "none", CVAR_NONE | CVAR_ROM, 0, + joy_device = Cvar_Get ("joy_device", "none", CVAR_ROM, 0, "Joystick device"); - joy_enable = Cvar_Get ("joy_enable", "1", CVAR_NONE | CVAR_ARCHIVE, 0, + joy_enable = Cvar_Get ("joy_enable", "1", CVAR_ARCHIVE, 0, "Joystick enable flag"); - joy_sensitivity = Cvar_Get ("joy_sensitivity", "1", CVAR_NONE | - CVAR_ARCHIVE, 0, "Joystick sensitivity"); + joy_sensitivity = Cvar_Get ("joy_sensitivity", "1", CVAR_ARCHIVE, 0, "Joystick sensitivity"); in_joystick = Cvar_Get ("joystick", "0", CVAR_ARCHIVE, 0, "FIXME: No " "Description"); joy_name = Cvar_Get ("joyname", "joystick", CVAR_NONE, 0, "FIXME: No " From f15abcea537f1236c7d3c63d9095415b3bff3359 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Apr 2022 10:46:55 +0900 Subject: [PATCH 30/77] [vulkan] Add a FIXME for the flashing Q icon As I had suspected, it's due to a synchronization problem between the scrap and drawing. There's actually a double problem in that data uploaded to the scrap isn't flushed until the first frame is rendered causing a quick init-shutdown sequence to take at least five seconds due to the staging buffer waiting (and timing out) on a stuck fence. Rendering just one frame "fixes" the problem (draw was one of the earliest subsystems to get going in vulkan). --- libs/video/renderer/vulkan/vulkan_draw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 24c11db91..7552b9a2a 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -276,6 +276,11 @@ pic_data (const char *name, int w, int h, const byte *data, drawctx_t *dctx) *picdata++ = *col++; *picdata++ = (pix == 255) - 1; } + //FIXME live updates of the scrap aren't + //syncronized properly for some reason and result in stale texels being + //rendered (flashing pink around the Q menu cursor the first time it's + //displayed). I suspect simple barriers aren't enough and more + //sophisticated syncronization (events? semaphores?) is needed. return pic; } From bc1fe6aa0133c5a6d09fc738d20f93fd0599013a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Apr 2022 10:56:56 +0900 Subject: [PATCH 31/77] [renderer] Remove some redundant comments No need for comments when the code says it all. --- libs/video/renderer/r_screen.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index cabd491cc..5d2d69ac6 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -74,37 +74,37 @@ static float tan_fov_x, tan_fov_y; static mat4f_t box_rotations[] = { [BOX_FRONT] = { - { 1, 0, 0, 0}, // front + { 1, 0, 0, 0}, { 0, 1, 0, 0}, { 0, 0, 1, 0}, { 0, 0, 0, 1} }, [BOX_RIGHT] = { - { 0,-1, 0, 0}, // right + { 0,-1, 0, 0}, { 1, 0, 0, 0}, { 0, 0, 1, 0}, { 0, 0, 0, 1} }, [BOX_BEHIND] = { - {-1, 0, 0, 0}, // back + {-1, 0, 0, 0}, { 0,-1, 0, 0}, { 0, 0, 1, 0}, { 0, 0, 0, 1} }, [BOX_LEFT] = { - { 0, 1, 0, 0}, // left + { 0, 1, 0, 0}, {-1, 0, 0, 0}, { 0, 0, 1, 0}, { 0, 0, 0, 1} }, [BOX_TOP] = { - { 0, 0, 1, 0}, // top + { 0, 0, 1, 0}, { 0, 1, 0, 0}, {-1, 0, 0, 0}, { 0, 0, 0, 1} }, [BOX_BOTTOM] = { - { 0, 0,-1, 0}, // bottom + { 0, 0,-1, 0}, { 0, 1, 0, 0}, { 1, 0, 0, 0}, { 0, 0, 0, 1} From 98cbacfe9df97fae5a7627a973cea48108c13690 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 07:14:03 +0900 Subject: [PATCH 32/77] [renderer] Remove redundant calls to visit_leaf I doubt the calls were ever actually made in a normal map due to the node actually being a node when breaking out of the loop, but when I experimented with an empty world model (no nodes, one infinite empty leaf) I found that visit_leaf was getting called twice instead of once. --- libs/video/renderer/gl/gl_rsurf.c | 2 -- libs/video/renderer/glsl/glsl_bsp.c | 2 -- libs/video/renderer/sw/sw_rbsp.c | 2 -- libs/video/renderer/vulkan/vulkan_bsp.c | 2 -- 4 files changed, 8 deletions(-) diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index c9c143c08..a796c1462 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -712,8 +712,6 @@ R_VisitWorldNodes (glbspctx_t *bctx) } break; } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); } void diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index cfdcec3b9..a4bd95182 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -831,8 +831,6 @@ R_VisitWorldNodes (glslbspctx_t *bctx) } break; } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); } static void diff --git a/libs/video/renderer/sw/sw_rbsp.c b/libs/video/renderer/sw/sw_rbsp.c index 81c8efc44..1362f9436 100644 --- a/libs/video/renderer/sw/sw_rbsp.c +++ b/libs/video/renderer/sw/sw_rbsp.c @@ -513,8 +513,6 @@ R_VisitWorldNodes (swbspctx_t *bctx, int clipflags) } break; } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); } void diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 336c4b08a..c7ee0cd2e 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -746,8 +746,6 @@ R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx) } break; } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); } static void From a9b8241a744841b5b809a858867b38f53cd911ab Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 07:19:35 +0900 Subject: [PATCH 33/77] [ruamoko] Fix some misnamed parameters IN_GetButtonName and IN_GetButtonNumber mentioned axis instead of button. A tad confusing. --- ruamoko/include/input.h | 4 ++-- ruamoko/lib/input.r | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ruamoko/include/input.h b/ruamoko/include/input.h index 31408cfc9..511d43e4e 100644 --- a/ruamoko/include/input.h +++ b/ruamoko/include/input.h @@ -13,9 +13,9 @@ string IN_GetDeviceId (int devid); //IN_AxisInfo (); //IN_ButtonInfo (); string IN_GetAxisName (int devid, int axis); -string IN_GetButtonName (int devid, int axis); +string IN_GetButtonName (int devid, int button); int IN_GetAxisNumber (int devid, string axis); -int IN_GetButtonNumber (int devid, string axis); +int IN_GetButtonNumber (int devid, string button); void IN_ProcessEvents (void); void IN_ClearStates (void); int IN_GetAxisInfo (int devid, int axis, in_axisinfo_t *info); diff --git a/ruamoko/lib/input.r b/ruamoko/lib/input.r index 34059f853..fa91c6b1f 100644 --- a/ruamoko/lib/input.r +++ b/ruamoko/lib/input.r @@ -9,9 +9,9 @@ string IN_GetDeviceId (int devid) = #0; //IN_AxisInfo () = #0; //IN_ButtonInfo () = #0; string IN_GetAxisName (int devid, int axis) = #0; -string IN_GetButtonName (int devid, int axis) = #0; +string IN_GetButtonName (int devid, int button) = #0; int IN_GetAxisNumber (int devid, string axis) = #0; -int IN_GetButtonNumber (int devid, string axis) = #0; +int IN_GetButtonNumber (int devid, string button) = #0; void IN_ProcessEvents (void) = #0; void IN_ClearStates (void) = #0; int IN_GetAxisInfo (int devid, int axis, in_axisinfo_t *info) = #0; From 5703df00fd27ee81d33888c075d2b445f3192d18 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 07:22:45 +0900 Subject: [PATCH 34/77] [renderer] Don't try to draw a nonexistent view model Doing so doesn't end well (segfault). This is a bit of a hack until I come up with a design for configurable scene rendering. --- libs/video/renderer/gl/gl_rmain.c | 4 +++- libs/video/renderer/glsl/glsl_main.c | 4 +++- libs/video/renderer/sw/sw_rmain.c | 4 +++- libs/video/renderer/vulkan/vulkan_main.c | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 720bf9469..6d171ac82 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -278,7 +278,9 @@ gl_R_RenderView (void) gl_R_DrawWorld (); S_ExtraUpdate (); // don't let sound get messed up if going slow gl_R_RenderDlights (); - R_DrawViewModel (); + if (vr_data.view_model) { + R_DrawViewModel (); + } gl_Fog_DisableGFog (); } diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index a2fa1f8f6..ba5ef36f2 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -142,7 +142,9 @@ glsl_R_RenderView (void) R_SetupView (); glsl_R_DrawWorld (); glsl_R_DrawSky (); - R_DrawViewModel (); + if (vr_data.view_model) { + R_DrawViewModel (); + } } static void diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 9f9b852a3..e05755a80 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -589,7 +589,9 @@ R_RenderView_ (void) R_EdgeDrawing (r_ent_queue); - R_DrawViewModel (); + if (vr_data.view_model) { + R_DrawViewModel (); + } if (r_aliasstats) R_PrintAliasStats (); diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 4bb82ecbc..6acf30d09 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -122,7 +122,9 @@ Vulkan_RenderView (qfv_renderframe_t *rFrame) Vulkan_DrawWorld (rFrame); Vulkan_DrawSky (rFrame); - Vulkan_DrawViewModel (ctx); + if (vr_data.view_model) { + Vulkan_DrawViewModel (ctx); + } Vulkan_DrawWaterSurfaces (rFrame); Vulkan_Bsp_Flush (ctx); } From c4d56afd335b0dcb647f479a3a385739d79c4fea Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 07:26:32 +0900 Subject: [PATCH 35/77] [vulkan] Cope with an empty world model Vulkan doesn't appreciate the empty buffers that result from the model not having any textures or surfaces that can be rendered (rightfully so, for such a bare-metal api). --- libs/models/brush/vulkan_model_brush.c | 4 +++- libs/video/renderer/vulkan/vulkan_bsp.c | 10 ++++++++++ libs/video/renderer/vulkan/vulkan_lighting.c | 18 ++++++++++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index 2fcc9f5bd..b1933de59 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -303,7 +303,9 @@ Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, vulkan_ctx_t *ctx) mod->data = mctx; r_notexture_mip->render = &vulkan_notexture; - load_textures (mod, ctx); + if (mod->brush.numtextures) { + load_textures (mod, ctx); + } return; } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index c7ee0cd2e..b202fd988 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -413,6 +413,10 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) bsppoly_t *poly; mod_brush_t *brush; + if (!num_models) { + return; + } + // run through all surfaces, chaining them to their textures, thus // effectively sorting the surfaces by texture (without worrying about // surface order on the same texture chain). @@ -1037,6 +1041,9 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame) bctx->color = 0; R_VisitWorldNodes (brush, ctx); + if (!bctx->vertex_buffer) { + return; + } if (r_drawentities) { for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; @@ -1089,6 +1096,9 @@ Vulkan_Bsp_Flush (vulkan_ctx_t *ctx) size_t offset = bframe->index_offset; size_t size = bframe->index_count * sizeof (uint32_t); + if (!bframe->index_count) { + return; + } offset &= ~atom_mask; size = (size + atom_mask) & ~atom_mask; diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 83e7e6fdc..33b13a22d 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -927,6 +927,10 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) lightingctx_t *lctx = ctx->lighting_context; plitem_t *entities = 0; + if (!entity_data) { + return; + } + lctx->lights.size = 0; lctx->lightleafs.size = 0; lctx->lightmats.size = 0; @@ -1006,11 +1010,13 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) PL_Free (entities); } Sys_MaskPrintf (SYS_vulkan, "loaded %zd lights\n", lctx->lights.size); - build_shadow_maps (lctx, ctx); - create_light_matrices (lctx); - locate_lights (model, lctx); - for (size_t i = 0; i < lctx->lights.size; i++) { - dump_light (&lctx->lights.a[i], lctx->lightleafs.a[i], - lctx->lightmats.a[i]); + if (lctx->lights.size) { + build_shadow_maps (lctx, ctx); + create_light_matrices (lctx); + locate_lights (model, lctx); + for (size_t i = 0; i < lctx->lights.size; i++) { + dump_light (&lctx->lights.a[i], lctx->lightleafs.a[i], + lctx->lightmats.a[i]); + } } } From 5c67f95edd0ae0d8f2f69ba6cbe2f99f0c63780c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Apr 2022 07:34:53 +0900 Subject: [PATCH 36/77] [qwaq] Set the world model to an empty world The goal is to have somewhere to put entities so they can be rendered. I suspect I could have used a bsp tree to partition space for frustum culling, but it's probably not worth it at this stage (but shouldn't require any changes to the engine: just the model). --- ruamoko/qwaq/builtins/graphics.c | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/ruamoko/qwaq/builtins/graphics.c b/ruamoko/qwaq/builtins/graphics.c index 1d6841998..0e272a07a 100644 --- a/ruamoko/qwaq/builtins/graphics.c +++ b/ruamoko/qwaq/builtins/graphics.c @@ -86,6 +86,40 @@ static progs_t *bi_rprogs; static pr_func_t qc2d; static int event_handler_id; +static mleaf_t empty_leafs[] = { + [1] = { + .contents = CONTENTS_EMPTY, + .mins = {-INFINITY, -INFINITY, -INFINITY}, + .maxs = { INFINITY, INFINITY, INFINITY}, + }, +}; + +static mnode_t *empty_leaf_parents[] = { + [1] = 0, +}; + +static int empty_leaf_flags[] = { + [1] = 0, +}; + +static char empty_entities[] = { 0 }; + +static model_t empty_world = { + .type = mod_brush, + .radius = INFINITY, + .mins = {-INFINITY, -INFINITY, -INFINITY}, + .maxs = { INFINITY, INFINITY, INFINITY}, + .brush = { + .modleafs = 2, + .visleafs = 1, + .nodes = (mnode_t *) &empty_leafs[1], + .leafs = empty_leafs, + .entities = empty_entities, + .leaf_parents = empty_leaf_parents, + .leaf_flags = empty_leaf_flags, + }, +}; + static void bi_2d (void) { @@ -196,4 +230,8 @@ BI_Graphics_Init (progs_t *pr) //CDAudio_Init (); Con_NewMap (); basetime = Sys_DoubleTime (); + if (mod_funcs->Mod_ProcessTexture) { + mod_funcs->Mod_ProcessTexture (&empty_world, 0); + } + r_funcs->R_NewMap (&empty_world, 0, 0); } From ef6e4722d52a6ebf6be0763f35a13bcfd4fbdfdf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 13:48:34 +0900 Subject: [PATCH 37/77] [simd] Add some comments to mat4fquat Having to refigure out what values are going into the vectors got old very fast. The comments don't help with verifying the values, but at least I can tell at a glance where 2(xy - wz) goes and thus determine the "orientation" of the matrix. --- include/QF/simd/mat4f.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/QF/simd/mat4f.h b/include/QF/simd/mat4f.h index d442bdac9..981d71d22 100644 --- a/include/QF/simd/mat4f.h +++ b/include/QF/simd/mat4f.h @@ -175,7 +175,7 @@ mat4fquat (mat4f_t m, vec4f_t q) vec4f_t b = _mm_xor_ps (shuff103 (yq), (__m128) mpm); vec4f_t c = _mm_xor_ps (shuff230 (zq), (__m128) pmm); vec4f_t d = _mm_xor_ps (shuff321 (wq), (__m128) mmp); - + // column: ww + xx - yy - zz // 2xy + 2wz // 2zx - 2wy // 0 m[0] = _mm_and_ps (a + b - c - d, (__m128) mask); } { @@ -183,6 +183,7 @@ mat4fquat (mat4f_t m, vec4f_t q) vec4f_t b = yq; vec4f_t c = _mm_xor_ps (shuff321 (zq), (__m128) mmp); vec4f_t d = _mm_xor_ps (shuff230 (wq), (__m128) pmm); + // column: 2xy - 2wz // ww - xx + yy - zz // 2yz + 2wx // 0 m[1] = _mm_and_ps (b + c - a - d, (__m128) mask); } { @@ -190,6 +191,7 @@ mat4fquat (mat4f_t m, vec4f_t q) vec4f_t b = _mm_xor_ps (shuff321 (yq), (__m128) mmp); vec4f_t c = zq; vec4f_t d = _mm_xor_ps (shuff103 (wq), (__m128) mpm); + // column: 2xz + 2wy // 2yz - 2wx // ww - xx - yy + zz // 0 m[2] = _mm_and_ps (a - b + c - d, (__m128) mask); } m[3] = (vec4f_t) { 0, 0, 0, 1 }; From 419d91edc5ded36345458385d69271ac9fe9d7d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 13:50:55 +0900 Subject: [PATCH 38/77] [image] Set texture type for no-load tga images I might need to do similar for other formats, but i ran into the problem of the texture type being tex_palette instead of the expected tex_rgba when pre-(no-)loading a tga image resulting in Vulkan not liking my attempt at generating mipmaps. --- include/QF/tga.h | 11 +++++++++++ libs/image/tga.c | 31 +++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/include/QF/tga.h b/include/QF/tga.h index 08d610d95..a5a133da3 100644 --- a/include/QF/tga.h +++ b/include/QF/tga.h @@ -44,6 +44,17 @@ # endif #endif +typedef enum { + targa_colormap = 1, + targa_truecolor = 2, + targa_greyscale = 3, + targa_colormap_rle = 9, + targa_truecolor_rle = 10, + targa_greyscale_rle = 11, + + targa_max_image_type = 15 +} TargaImageType; + typedef struct _TargaHeader { unsigned char id_length; // __attribute__((packed)); unsigned char colormap_type; // __attribute__((packed)); diff --git a/libs/image/tga.c b/libs/image/tga.c index 20db43ddd..03368ce6f 100644 --- a/libs/image/tga.c +++ b/libs/image/tga.c @@ -605,19 +605,25 @@ decode_greyscale_rle (TargaHeader *targa, tex_t *tex, byte *dataByte) typedef void (*decoder_t) (TargaHeader *, tex_t *, byte *); static decoder_t decoder_functions[] = { - 0, // 0 invalid - decode_colormap, - decode_truecolor, - decode_greyscale, - 0, 0, 0, 0, // 5-7 invalid - 0, // 8 invalid - decode_colormap_rle, - decode_truecolor_rle, - decode_greyscale_rle, - 0, 0, 0, 0, // 12-15 invalid + [targa_colormap] = decode_colormap, + [targa_truecolor] = decode_truecolor, + [targa_greyscale] = decode_greyscale, + [targa_colormap_rle] = decode_colormap_rle, + [targa_truecolor_rle] = decode_truecolor_rle, + [targa_greyscale_rle] = decode_greyscale_rle, + [targa_max_image_type] = 0 }; #define NUM_DECODERS (sizeof (decoder_functions) \ / sizeof (decoder_functions[0])) +static QFFormat targa_formats[] = { + [targa_colormap] = tex_palette, + [targa_truecolor] = tex_rgba, + [targa_greyscale] = tex_l, + [targa_colormap_rle] = tex_palette, + [targa_truecolor_rle] = tex_rgba, + [targa_greyscale_rle] = tex_l, + [targa_max_image_type] = 0 +}; struct tex_s * LoadTGA (QFile *fin, int load) @@ -669,6 +675,11 @@ LoadTGA (QFile *fin, int load) dataByte += targa->id_length; decode (targa, tex, dataByte); + } else { + //FIXME + // assume the format is valid so we can return a format type without + // having to check individial image type specific data + tex->format = targa_formats[targa->image_type]; } Hunk_FreeToLowMark (0, targa_mark); From a77aa1631804d0b6985ab6bd27de1d41aa87ef93 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 13:55:56 +0900 Subject: [PATCH 39/77] [vulkan] Make some headers order-indepenedent In that they don't need Vulkan/qf_vid.h included first. --- include/QF/Vulkan/barrier.h | 5 +++++ include/QF/Vulkan/buffer.h | 5 +++++ include/QF/Vulkan/image.h | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/include/QF/Vulkan/barrier.h b/include/QF/Vulkan/barrier.h index a28e07817..52be26b08 100644 --- a/include/QF/Vulkan/barrier.h +++ b/include/QF/Vulkan/barrier.h @@ -1,6 +1,11 @@ #ifndef __QF_Vulkan_barrier_h #define __QF_Vulkan_barrier_h +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + typedef struct { VkPipelineStageFlags srcStages; VkPipelineStageFlags dstStages; diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h index 374a496b1..2edff6a1d 100644 --- a/include/QF/Vulkan/buffer.h +++ b/include/QF/Vulkan/buffer.h @@ -1,6 +1,11 @@ #ifndef __QF_Vulkan_buffer_h #define __QF_Vulkan_buffer_h +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + #include "QF/darray.h" typedef struct qfv_buffertransition_s { diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index d146b298c..0f10b3092 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -1,6 +1,11 @@ #ifndef __QF_Vulkan_image_h #define __QF_Vulkan_image_h +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + #include "QF/darray.h" typedef struct qfv_imageset_s From 9d7cad420da8689572058b6adda99b248270d91b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 13:57:02 +0900 Subject: [PATCH 40/77] [vulkan] Add a function to translate QFFormat to VkFormat It's not great, but it does produce reasonable results for the formats supported by QF's image system. --- include/QF/Vulkan/image.h | 11 +++++++++++ libs/video/renderer/vulkan/image.c | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 0f10b3092..3524b27ee 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -7,6 +7,7 @@ #include #include "QF/darray.h" +#include "QF/image.h" typedef struct qfv_imageset_s DARRAY_TYPE (VkImage) qfv_imageset_t; @@ -100,4 +101,14 @@ void QFV_GenerateMipMaps (struct qfv_device_s *device, VkCommandBuffer cmd, unsigned width, unsigned height, unsigned layers); int QFV_MipLevels (int width, int height) __attribute__((const)); +/** Convert QFFormat to VkFormat + * + * \param format The format to convert. + * \return The corresponding VkFormat. + * + * \note For tex_palette, VK_FORMAT_R8_UINT is returned. If \a format is + * not a valid QFFormat, then VK_FORMAT_R8_SRGB is returned. + */ +VkFormat QFV_ImageFormat (QFFormat format); + #endif//__QF_Vulkan_image_h diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 092af713a..27bb3cf7b 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -266,3 +266,24 @@ QFV_MipLevels (int width, int height) { return ilog2 (max (width, height)) + 1; } + +VkFormat +QFV_ImageFormat (QFFormat format) +{ + switch (format) { + case tex_palette: + return VK_FORMAT_R8_UINT; + case tex_l: + case tex_a: + return VK_FORMAT_R8_UNORM; + case tex_la: + return VK_FORMAT_R8G8_UNORM; + case tex_rgb: + return VK_FORMAT_R8G8B8_UNORM; // SRGB? + case tex_rgba: + return VK_FORMAT_R8G8B8A8_UNORM;// SRGB? + case tex_frgba: + return VK_FORMAT_R32G32B32A32_SFLOAT; + } + return VK_FORMAT_R8_SRGB; +} From a4f500da3c3f3e8b9b51cf680e27db03c865e19d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 13:59:38 +0900 Subject: [PATCH 41/77] [vulkan] Add a mini resource subsystem The resource subsystem creates buffers, images, buffer views and image views in a single batch operation, using a single memory object to back all the buffers and images. I had been doing this by hand for a while, but got tired of jumping through all those vulkan hoops. While it's still a little tedious to set up the arrays for QFV_CreateResource (and they need to be kept around for QFV_DestroyResource), it really eases calculation of memory object size and sub-resource offsets. And destroying all the objects is just one call to QFV_DestroyResource. --- include/QF/Vulkan/resource.h | 68 +++++++ libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/vulkan/resource.c | 271 ++++++++++++++++++++++++++ 3 files changed, 340 insertions(+) create mode 100644 include/QF/Vulkan/resource.h create mode 100644 libs/video/renderer/vulkan/resource.c diff --git a/include/QF/Vulkan/resource.h b/include/QF/Vulkan/resource.h new file mode 100644 index 000000000..7d1e0dac6 --- /dev/null +++ b/include/QF/Vulkan/resource.h @@ -0,0 +1,68 @@ +#ifndef __QF_Vulkan_resource_h +#define __QF_Vulkan_resource_h + +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + +typedef enum { + qfv_res_buffer = 1, + qfv_res_buffer_view, + qfv_res_image, + qfv_res_image_view, +} qfv_res_type; + +typedef struct qfv_resobj_s { + const char *name; + qfv_res_type type; + union { + struct { + VkDeviceSize size; + VkBufferUsageFlags usage; + VkBuffer buffer; + } buffer; + struct { + unsigned buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize size; + VkBufferView view; + } buffer_view; + struct { + int cubemap; + VkImageType type; + VkFormat format; + VkExtent3D extent; + uint32_t num_mipmaps; + uint32_t num_layers; + VkSampleCountFlags samples; + VkImageUsageFlags usage; + VkImage image; + } image; + struct { + unsigned image; + VkImageViewType type; + VkFormat format; + VkImageAspectFlags aspect; + VkImageView view; + } image_view; + }; +} qfv_resobj_t; + +typedef struct qfv_resource_s { + const char *name; + struct va_ctx_s *va_ctx; + VkMemoryPropertyFlags memory_properties; + unsigned num_objects; + qfv_resobj_t *objects; + VkDeviceMemory memory; +} qfv_resource_t; + +struct qfv_device_s; + +int QFV_CreateResource (struct qfv_device_s *device, qfv_resource_t *resource); +void QFV_DestroyResource (struct qfv_device_s *device, + qfv_resource_t *resource); + +#endif//__QF_Vulkan_resource_h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 2743a4a68..eceb2a1c2 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -207,6 +207,7 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/pipeline.c \ libs/video/renderer/vulkan/projection.c \ libs/video/renderer/vulkan/renderpass.c \ + libs/video/renderer/vulkan/resource.c \ libs/video/renderer/vulkan/scrap.c \ libs/video/renderer/vulkan/shader.c \ libs/video/renderer/vulkan/staging.c \ diff --git a/libs/video/renderer/vulkan/resource.c b/libs/video/renderer/vulkan/resource.c new file mode 100644 index 000000000..2eb08e6d7 --- /dev/null +++ b/libs/video/renderer/vulkan/resource.c @@ -0,0 +1,271 @@ +/* + resource.c + + Vulkan resource functions + + Copyright (C) 2022 Bill Currie + + 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 + +#include "QF/va.h" + +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/resource.h" + +int +QFV_CreateResource (qfv_device_t *device, qfv_resource_t *resource) +{ + qfv_devfuncs_t *dfunc = device->funcs; + qfv_physdev_t *physdev = device->physDev; + VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; + VkMemoryRequirements req; + VkDeviceSize size = 0; + + for (unsigned i = 0; i < resource->num_objects; i++) { + __auto_type obj = &resource->objects[i]; + switch (obj->type) { + case qfv_res_buffer: + { + __auto_type buffer = &obj->buffer; + buffer->buffer = QFV_CreateBuffer (device, + buffer->size, + buffer->usage); + const char *name = va (resource->va_ctx, "buffer:%s:%s", + resource->name, obj->name); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, + buffer->buffer, name); + dfunc->vkGetBufferMemoryRequirements (device->dev, + buffer->buffer, &req); + } + break; + case qfv_res_buffer_view: + { + __auto_type buffview = &obj->buffer_view; + __auto_type buffobj = &resource->objects[buffview->buffer]; + if (buffview->buffer >= resource->num_objects + || buffobj->type != qfv_res_buffer) { + Sys_Error ("%s:%s invalid buffer for view", + resource->name, obj->name); + } + } + break; + case qfv_res_image: + { + __auto_type image = &obj->image; + image->image = QFV_CreateImage (device, + image->cubemap, + image->type, + image->format, + image->extent, + image->num_mipmaps, + image->num_layers, + image->samples, + image->usage); + const char *name = va (resource->va_ctx, "image:%s:%s", + resource->name, obj->name); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, + image->image, name); + dfunc->vkGetImageMemoryRequirements (device->dev, + image->image, &req); + } + break; + case qfv_res_image_view: + { + __auto_type imgview = &obj->image_view; + __auto_type imgobj = &resource->objects[imgview->image]; + if (imgview->image >= resource->num_objects + || imgobj->type != qfv_res_image) { + Sys_Error ("%s:%s invalid image for view", + resource->name, obj->name); + } + } + break; + default: + Sys_Error ("%s:%s invalid resource type %d", + resource->name, obj->name, obj->type); + } + size = QFV_NextOffset (size, &req); + size += req.size; + } + VkMemoryPropertyFlags properties = resource->memory_properties; + for (uint32_t type = 0; type < memprops->memoryTypeCount; type++) { + if ((req.memoryTypeBits & (1 << type)) + && ((memprops->memoryTypes[type].propertyFlags & properties) + == properties)) { + VkMemoryAllocateInfo allocate_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = size, + .memoryTypeIndex = type, + }; + VkResult res = dfunc->vkAllocateMemory (device->dev, &allocate_info, + 0, &resource->memory); + if (res == VK_SUCCESS) { + break; + } + } + } + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + resource->memory, va (resource->va_ctx, "memory:%s", + resource->name)); + + VkDeviceSize offset = 0; + for (unsigned i = 0; i < resource->num_objects; i++) { + __auto_type obj = &resource->objects[i]; + switch (obj->type) { + case qfv_res_buffer: + { + __auto_type buffer = &obj->buffer; + dfunc->vkGetBufferMemoryRequirements (device->dev, + buffer->buffer, &req); + } + break; + case qfv_res_image: + { + __auto_type image = &obj->image; + dfunc->vkGetImageMemoryRequirements (device->dev, + image->image, &req); + } + break; + case qfv_res_buffer_view: + case qfv_res_image_view: + break; + } + + offset = QFV_NextOffset (offset, &req); + switch (obj->type) { + case qfv_res_buffer: + { + __auto_type buffer = &obj->buffer; + QFV_BindBufferMemory (device, buffer->buffer, + resource->memory, offset); + } + break; + case qfv_res_image: + { + __auto_type image = &obj->image; + QFV_BindImageMemory (device, image->image, + resource->memory, offset); + } + break; + case qfv_res_buffer_view: + case qfv_res_image_view: + break; + } + offset += req.size; + } + + for (unsigned i = 0; i < resource->num_objects; i++) { + __auto_type obj = &resource->objects[i]; + switch (obj->type) { + case qfv_res_buffer: + case qfv_res_image: + break; + case qfv_res_buffer_view: + { + __auto_type buffview = &obj->buffer_view; + __auto_type buffobj = &resource->objects[buffview->buffer]; + __auto_type buffer = &buffobj->buffer; + buffview->view = QFV_CreateBufferView (device, + buffer->buffer, + buffview->format, + buffview->offset, + buffview->size); + const char *name = va (resource->va_ctx, "bview:%s:%s", + resource->name, obj->name); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER_VIEW, + buffview->view, name); + } + break; + case qfv_res_image_view: + { + __auto_type imgview = &obj->image_view; + __auto_type imgobj = &resource->objects[imgview->image]; + __auto_type image = &imgobj->image; + imgview->view = QFV_CreateImageView (device, + image->image, + imgview->type, + imgview->format, + imgview->aspect); + const char *name = va (resource->va_ctx, "iview:%s:%s", + resource->name, obj->name); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, + imgview->view, name); + } + break; + } + } + return 0; +} + +void +QFV_DestroyResource (qfv_device_t *device, qfv_resource_t *resource) +{ + qfv_devfuncs_t *dfunc = device->funcs; + + for (unsigned i = 0; i < resource->num_objects; i++) { + __auto_type obj = &resource->objects[i]; + switch (obj->type) { + case qfv_res_buffer: + case qfv_res_image: + break; + case qfv_res_buffer_view: + { + __auto_type buffview = &obj->buffer_view; + dfunc->vkDestroyBufferView (device->dev, buffview->view, 0); + } + break; + case qfv_res_image_view: + { + __auto_type imgview = &obj->image_view; + dfunc->vkDestroyImageView (device->dev, imgview->view, 0); + } + break; + } + } + for (unsigned i = 0; i < resource->num_objects; i++) { + __auto_type obj = &resource->objects[i]; + switch (obj->type) { + case qfv_res_buffer: + { + __auto_type buffer = &obj->buffer; + dfunc->vkDestroyBuffer (device->dev, buffer->buffer, 0); + } + break; + case qfv_res_image: + { + __auto_type image = &obj->image; + dfunc->vkDestroyImage (device->dev, image->image, 0); + } + break; + case qfv_res_buffer_view: + case qfv_res_image_view: + break; + } + } + dfunc->vkFreeMemory (device->dev, resource->memory, 0); +} From bbca22c722412dd0b5c297a7cddc3b8947ff1569 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:07:27 +0900 Subject: [PATCH 42/77] [vulkan] Add support for IQM models Despite the base IQM specification not supporting blend-shapes, I think IQM will become the basis for QF's generic model representation (at least for the more advanced renderers). After my experience with .mu models (KSP) and unity mesh objects (both normal and skinned), and reviewing the IQM spec, it looks like with the addition of support for blend-shapes, IQM is actually pretty good. This is just the preliminary work to get standard IQM models loading in vulkan (seems to work, along with unloading), and they very basics into the renderer (most likely not working: not tested yet). The rest of the renderer seems to be unaffected, though, which is good. --- include/QF/Vulkan/qf_iqm.h | 113 +++++ include/vid_vulkan.h | 1 + libs/models/iqm/vulkan_model_iqm.c | 468 +++++++++++++++++++++ libs/video/renderer/Makemodule.am | 13 +- libs/video/renderer/vid_render_vulkan.c | 2 + libs/video/renderer/vulkan/iqm.plist | 254 +++++++++++ libs/video/renderer/vulkan/shader.c | 6 + libs/video/renderer/vulkan/shader/iqm.frag | 44 ++ libs/video/renderer/vulkan/shader/iqm.vert | 52 +++ libs/video/renderer/vulkan/vulkan_iqm.c | 310 ++++++++++++++ 10 files changed, 1262 insertions(+), 1 deletion(-) create mode 100644 include/QF/Vulkan/qf_iqm.h create mode 100644 libs/video/renderer/vulkan/iqm.plist create mode 100644 libs/video/renderer/vulkan/shader/iqm.frag create mode 100644 libs/video/renderer/vulkan/shader/iqm.vert create mode 100644 libs/video/renderer/vulkan/vulkan_iqm.c diff --git a/include/QF/Vulkan/qf_iqm.h b/include/QF/Vulkan/qf_iqm.h new file mode 100644 index 000000000..7de1623d9 --- /dev/null +++ b/include/QF/Vulkan/qf_iqm.h @@ -0,0 +1,113 @@ +/* + qf_iqm.h + + Vulkan specific iqm model stuff + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/5/3 + + 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 + +*/ +#ifndef __QF_Vulkan_qf_iqm_h +#define __QF_Vulkan_qf_iqm_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +// geometry attributes +typedef struct iqmgvert_s { + float vertex[3]; + byte bones[4]; // uint + byte weights[4]; // unorm +} iqmgvert_t; + +// rendering attributes +typedef struct iqmrvert_s { + float uv[2]; + float normal[3]; + float tangent[4]; + byte color[4]; // unorm +} iqmrvert_t; + +typedef struct qfv_iqm_skin_s { + VkImageView view; + byte colora[4]; + byte colorb[4]; + VkDescriptorSet descriptor; +} qfv_iqm_skin_t; + +typedef struct qfv_iqm_s { + VkBuffer geom_buffer; + VkBuffer rend_buffer; + VkBuffer index_buffer; + qfv_iqm_skin_t *skins; + struct qfv_resource_s *mesh; + struct qfv_resource_s *bones; +} qfv_iqm_t; + +typedef enum { + QFV_iqmDepth, + QFV_iqmGBuffer, + QFV_iqmTranslucent, + + QFV_iqmNumPasses +} QFV_IQMSubpass; + +typedef struct iqm_frame_s { + qfv_cmdbufferset_t cmdSet; +} iqm_frame_t; + +typedef struct iqm_frameset_s + DARRAY_TYPE (iqm_frame_t) iqm_frameset_t; + +typedef struct iqmindset_s + DARRAY_TYPE (unsigned) iqmindset_t; + +typedef struct iqmctx_s { + iqm_frameset_t frames; + VkPipeline depth; + VkPipeline gbuf; + VkPipelineLayout layout; + VkSampler sampler; +} iqmctx_t; + +struct vulkan_ctx_s; +struct qfv_renderframe_s; +struct entity_s; +struct mod_iqm_ctx_s; + +void Vulkan_Mod_IQMFinish (struct model_s *mod, struct vulkan_ctx_s *ctx); + +void Vulkan_IQMAddSkin (struct vulkan_ctx_s *ctx, qfv_iqm_skin_t *skin); +void Vulkan_IQMRemoveSkin (struct vulkan_ctx_s *ctx, qfv_iqm_skin_t *skin); + +void Vulkan_IQMBegin (struct qfv_renderframe_s *rFrame); +void Vulkan_DrawIQM (struct entity_s *ent, struct qfv_renderframe_s *rFrame); +void Vulkan_IQMEnd (struct qfv_renderframe_s *rFrame); + +void Vulkan_IQM_Init (struct vulkan_ctx_s *ctx); +void Vulkan_IQM_Shutdown (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_iqm_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index e5bd29022..df1e4b6bd 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -67,6 +67,7 @@ typedef struct vulkan_ctx_s { struct matrixctx_s *matrix_context; struct aliasctx_s *alias_context; struct bspctx_s *bsp_context; + struct iqmctx_s *iqm_context; struct particlectx_s *particle_context; struct spritectx_s *sprite_context; struct drawctx_s *draw_context; diff --git a/libs/models/iqm/vulkan_model_iqm.c b/libs/models/iqm/vulkan_model_iqm.c index e69de29bb..c9c7f79c8 100644 --- a/libs/models/iqm/vulkan_model_iqm.c +++ b/libs/models/iqm/vulkan_model_iqm.c @@ -0,0 +1,468 @@ +/* + vulkan_model_iqm.c + + iqm model processing for Vulkan + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + Date: 2022/05/03 + + 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 +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/dstring.h" +#include "QF/image.h" +#include "QF/quakefs.h" +#include "QF/va.h" + +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/resource.h" +#include "QF/Vulkan/staging.h" +#include "QF/Vulkan/qf_iqm.h" +#include "QF/Vulkan/qf_texture.h" + +#include "mod_internal.h" +#include "r_shared.h" +#include "vid_vulkan.h" + +static byte null_texture[] = { + 204, 204, 204, 255, + 204, 204, 204, 255, + 204, 204, 204, 255, + 204, 204, 204, 255, +}; +#if 0 +static byte null_normmap[] = { + 127, 127, 255, 255, + 127, 127, 255, 255, + 127, 127, 255, 255, + 127, 127, 255, 255, +}; +#endif +static void +vulkan_iqm_clear (model_t *mod, void *data) +{ + vulkan_ctx_t *ctx = data; + qfv_device_t *device = ctx->device; + iqm_t *iqm = (iqm_t *) mod->aliashdr; + qfv_iqm_t *mesh = iqm->extra_data; + + mod->needload = true; + + QFV_DestroyResource (device, mesh->bones); + QFV_DestroyResource (device, mesh->mesh); + free (mesh); + Mod_FreeIQM (iqm); +} + +static void +vulkan_iqm_init_image (iqm_t *iqm, int meshnum, qfv_resobj_t *image) +{ + const char *material = iqm->text + iqm->meshes[meshnum].material; + dstring_t *str = dstring_new (); + dstring_copystr (str, material); + QFS_StripExtension (str->str, str->str); + + tex_t *tex; + if ((tex = LoadImage (va (0, "textures/%s", str->str), 0))) { + *image = (qfv_resobj_t) { + .name = material, + .type = qfv_res_image, + .image = { + .type = VK_IMAGE_TYPE_2D, + .format = QFV_ImageFormat (tex->format), + .extent = { + .width = tex->width, + .height = tex->height, + .depth = 1, + }, + .num_mipmaps = QFV_MipLevels (tex->width, tex->height), + .num_layers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, + }, + }; + } else { + *image = (qfv_resobj_t) { + .name = material, + .type = qfv_res_image, + .image = { + .type = VK_IMAGE_TYPE_2D, + .format = QFV_ImageFormat (tex_rgba), + .extent = { + .width = 2, + .height = 2, + .depth = 1, + }, + .num_mipmaps = QFV_MipLevels (2, 2), + .num_layers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, + }, + }; + } + dstring_delete (str); +} + +static void +iqm_transfer_texture (tex_t *tex, VkImage image, qfv_stagebuf_t *stage, + qfv_device_t *device) +{ + qfv_devfuncs_t *dfunc = device->funcs; + + if (tex->format != tex_rgb && tex->format != tex_rgba) { + Sys_Error ("can't transfer iqm image"); + } + // FIXME correct only for rgb and rgba + size_t layer_size = tex->width * tex->height * tex->format; + + qfv_packet_t *packet = QFV_PacketAcquire (stage); + byte *dst = QFV_PacketExtend (packet, layer_size); + + qfv_imagebarrier_t ib = imageBarriers[qfv_LT_Undefined_to_TransferDst]; + ib.barrier.image = image; + ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, + 1, &ib.barrier); + memcpy (dst, tex->data, layer_size); + + int mipLevels = QFV_MipLevels (tex->width, tex->height); + if (mipLevels == 1) { + ib = imageBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + ib.barrier.image = image; + ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, + 1, &ib.barrier); + } else { + QFV_GenerateMipMaps (device, packet->cmd, image, mipLevels, + tex->width, tex->height, 1); + } + QFV_PacketSubmit (packet); +} + +static void +vulkan_iqm_load_textures (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh, + vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + dstring_t *str = dstring_new (); + tex_t *tex; + size_t buff_size = 0; + qfv_resobj_t *objects = mesh->mesh->objects; + + for (int i = 0; i < iqm->num_meshes; i++) { + int image_ind = 3 + 2 * i; + VkExtent3D extent = objects[image_ind].image.extent; + // probably 3 or 4 bytes per pixel FIXME + buff_size = max (buff_size, extent.width * extent.height * 4); + } + + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, + va (ctx->va_ctx, "iqm:%s", + mod->name), + 4 * buff_size, + ctx->cmdpool); + + for (int i = 0; i < iqm->num_meshes; i++) { + int image_ind = 3 + 2 * i; + __auto_type image = &objects[image_ind].image; + __auto_type view = &objects[image_ind + 1].image_view; + qfv_iqm_skin_t *skin = &mesh->skins[i]; + *skin = (qfv_iqm_skin_t) { + .view = view->view, + .colora = { 255, 255, 255, 255 }, + .colorb = { 255, 255, 255, 255 }, + }; + + dstring_copystr (str, iqm->text + iqm->meshes[i].material); + QFS_StripExtension (str->str, str->str); + if (!(tex = LoadImage (va (0, "textures/%s", str->str), 1))) { + tex_t null_tex = { + .width = 2, + .height = 2, + .format = tex_rgba, + .data = null_texture, + }; + tex = &null_tex; + } + iqm_transfer_texture (tex, image->image, stage, device); + } + dstring_delete (str); + QFV_DestroyStagingBuffer (stage); +} + +static void +vulkan_iqm_load_arrays (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh, + vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + 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); + size_t buff_size = geom_size + rend_size + elem_size + 1024; + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, + va (ctx->va_ctx, "iqm:%s", + mod->name), + buff_size, ctx->cmdpool); + qfv_packet_t *gpacket = QFV_PacketAcquire (stage); + iqmgvert_t *gverts = QFV_PacketExtend (gpacket, geom_size); + qfv_packet_t *rpacket = QFV_PacketAcquire (stage); + iqmrvert_t *rverts = QFV_PacketExtend (rpacket, rend_size); + qfv_packet_t *epacket = QFV_PacketAcquire (stage); + uint16_t *elements = QFV_PacketExtend (epacket, elem_size); + //FIXME this whole thing is silly, but some person went and interleaved + //all the vertex data prematurely + for (int i = 0; i < iqm->num_verts; i++) { + byte *data = iqm->vertices + i * iqm->stride; + iqmgvert_t *gv = gverts + i; + iqmrvert_t *rv = rverts + i; + for (int j = 0; j < iqm->num_arrays; j++) { + __auto_type va = &iqm->vertexarrays[j]; + // FIXME assumes standard iqm sizes + size_t size = 0; + switch (va->type) { + case IQM_POSITION: + size = sizeof (gv->vertex); + memcpy (gv->vertex, data, size); + break; + case IQM_TEXCOORD: + size = sizeof (rv->uv); + memcpy (rv->uv, data, size); + break; + case IQM_NORMAL: + size = sizeof (rv->normal); + memcpy (rv->normal, data, size); + break; + case IQM_TANGENT: + size = sizeof (rv->tangent); + memcpy (rv->tangent, data, size); + break; + case IQM_BLENDINDEXES: + size = sizeof (gv->bones); + memcpy (gv->bones, data, size); + break; + case IQM_BLENDWEIGHTS: + size = sizeof (gv->weights); + memcpy (gv->weights, data, size); + break; + case IQM_COLOR: + size = sizeof (rv->color); + memcpy (rv->color, data, size); + break; + case IQM_CUSTOM: + // FIXME model loader doesn't handle these, so nothing to do + break; + } + data += size; + } + } + memcpy (elements, iqm->elements, elem_size); + + qfv_bufferbarrier_t bb[] = { + bufferBarriers[qfv_BB_Unknown_to_TransferWrite], + bufferBarriers[qfv_BB_Unknown_to_TransferWrite], + bufferBarriers[qfv_BB_Unknown_to_TransferWrite], + }; + bb[0].barrier.buffer = mesh->geom_buffer; + bb[0].barrier.size = geom_size; + bb[1].barrier.buffer = mesh->rend_buffer; + bb[1].barrier.size = rend_size; + bb[2].barrier.buffer = mesh->index_buffer; + bb[2].barrier.size = elem_size; + VkBufferCopy copy_region[] = { + { gpacket->offset, 0, geom_size }, + { rpacket->offset, 0, rend_size }, + { epacket->offset, 0, elem_size }, + }; + + dfunc->vkCmdPipelineBarrier (gpacket->cmd, bb[0].srcStages, bb[0].dstStages, + 0, 0, 0, 1, &bb[0].barrier, 0, 0); + dfunc->vkCmdPipelineBarrier (rpacket->cmd, bb[0].srcStages, bb[0].dstStages, + 0, 0, 0, 1, &bb[1].barrier, 0, 0); + dfunc->vkCmdPipelineBarrier (epacket->cmd, bb[0].srcStages, bb[0].dstStages, + 0, 0, 0, 1, &bb[2].barrier, 0, 0); + dfunc->vkCmdCopyBuffer (gpacket->cmd, stage->buffer, + mesh->geom_buffer, 1, ©_region[0]); + dfunc->vkCmdCopyBuffer (rpacket->cmd, stage->buffer, + mesh->rend_buffer, 1, ©_region[1]); + dfunc->vkCmdCopyBuffer (epacket->cmd, stage->buffer, + mesh->index_buffer, 1, ©_region[2]); + bb[0] = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]; + bb[1] = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]; + bb[2] = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]; + bb[0].barrier.buffer = mesh->geom_buffer; + bb[0].barrier.size = geom_size; + bb[1].barrier.buffer = mesh->rend_buffer; + bb[1].barrier.size = rend_size; + bb[2].barrier.buffer = mesh->index_buffer; + bb[2].barrier.size = elem_size; + dfunc->vkCmdPipelineBarrier (gpacket->cmd, bb[0].srcStages, bb[0].dstStages, + 0, 0, 0, 1, &bb[0].barrier, 0, 0); + dfunc->vkCmdPipelineBarrier (rpacket->cmd, bb[0].srcStages, bb[0].dstStages, + 0, 0, 0, 1, &bb[1].barrier, 0, 0); + dfunc->vkCmdPipelineBarrier (epacket->cmd, bb[0].srcStages, bb[0].dstStages, + 0, 0, 0, 1, &bb[2].barrier, 0, 0); + QFV_PacketSubmit (gpacket); + QFV_PacketSubmit (rpacket); + QFV_PacketSubmit (epacket); + QFV_DestroyStagingBuffer (stage); + + vec4f_t *bone_data; + dfunc->vkMapMemory (device->dev, mesh->bones->memory, 0, VK_WHOLE_SIZE, + 0, (void **)&bone_data); + for (int i = 0; i < 3 * iqm->num_joints; i++) { + vec4f_t *bone = bone_data + i * 3; + bone[0] = (vec4f_t) {1, 0, 0, 0}; + bone[1] = (vec4f_t) {0, 1, 0, 0}; + bone[2] = (vec4f_t) {0, 0, 1, 0}; + } + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + mesh->bones->memory, 0, VK_WHOLE_SIZE, + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); + + dfunc->vkUnmapMemory (device->dev, mesh->bones->memory); +} + +void +Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + iqm_t *iqm = (iqm_t *) mod->aliashdr; + mod->clear = vulkan_iqm_clear; + mod->data = ctx; + + // FIXME assumes only one texture per mesh (currently the case, but + // when materials are added...) + // 2 is for image + image view + int num_objects = 4 + 2 * iqm->num_meshes; + qfv_iqm_t *mesh = calloc (1, sizeof (qfv_iqm_t) + + 2 * sizeof (qfv_resource_t) + + num_objects * sizeof (qfv_resobj_t) + + iqm->num_meshes * sizeof (qfv_iqm_skin_t)); + mesh->bones = (qfv_resource_t *) &mesh[1]; + mesh->mesh = &mesh->bones[1]; + + mesh->bones[0] = (qfv_resource_t) { + .name = mod->name, + .va_ctx = ctx->va_ctx, + .memory_properties = VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + .num_objects = 1, + .objects = (qfv_resobj_t *) &mesh->bones[2], + }; + mesh->bones->objects[0] = (qfv_resobj_t) { + .name = "bones", + .type = qfv_res_buffer, + .buffer = { + .size = 3 * iqm->num_joints * 3 * sizeof (vec4f_t), + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + }, + }; + + mesh->mesh[0] = (qfv_resource_t) { + .name = "mesh", + .va_ctx = ctx->va_ctx, + .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .num_objects = num_objects - 1, + .objects = mesh->bones->objects + 1, + }; + mesh->mesh->objects[0] = (qfv_resobj_t) { + .name = "geom", + .type = qfv_res_buffer, + .buffer = { + .size = iqm->num_verts * sizeof (iqmgvert_t), + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + }, + }; + mesh->mesh->objects[1] = (qfv_resobj_t) { + .name = "rend", + .type = qfv_res_buffer, + .buffer = { + .size = iqm->num_verts * sizeof (iqmrvert_t), + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + }, + }; + mesh->mesh->objects[2] = (qfv_resobj_t) { + .name = "index", + .type = qfv_res_buffer, + .buffer = { + .size = iqm->num_elements * sizeof (uint16_t), + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + }, + }; + + for (int i = 0; i < iqm->num_meshes; i++) { + int image_ind = 3 + 2 * i; + __auto_type image = &mesh->mesh->objects[image_ind]; + vulkan_iqm_init_image (iqm, i, image); + + mesh->mesh->objects[image_ind + 1] = (qfv_resobj_t) { + .name = "view", + .type = qfv_res_image_view, + .image_view = { + .image = image_ind, + .type = VK_IMAGE_VIEW_TYPE_2D, + .format = mesh->mesh->objects[image_ind].image.format, + .aspect = VK_IMAGE_ASPECT_COLOR_BIT, + }, + }; + } + + mesh->skins = (qfv_iqm_skin_t *) &mesh->bones->objects[num_objects]; + + QFV_CreateResource (device, mesh->mesh); + QFV_CreateResource (device, mesh->bones); + mesh->geom_buffer = mesh->mesh->objects[0].buffer.buffer; + mesh->rend_buffer = mesh->mesh->objects[1].buffer.buffer; + mesh->index_buffer = mesh->mesh->objects[2].buffer.buffer; + + vulkan_iqm_load_textures (mod, iqm, mesh, ctx); + vulkan_iqm_load_arrays (mod, iqm, mesh, ctx); + + iqm->extra_data = mesh; +} diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index eceb2a1c2..5b3c981cd 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -91,7 +91,7 @@ libs_video_renderer_librender_gl_la_SOURCES = \ shader_src= libs/video/renderer/glsl/quakeforge.glsl shader_gen= libs/video/renderer/glsl/quakeforge.slc -SUFFICES += .frag .vert .spv .spvc .fc .vc .slc .glsl +SUFFIXES += .frag .vert .spv .spvc .fc .vc .slc .glsl .glsl.slc: $(V_SED)sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\ $(am__mv) $@.t $@ @@ -219,6 +219,7 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vulkan_bsp.c \ libs/video/renderer/vulkan/vulkan_compose.c \ libs/video/renderer/vulkan/vulkan_draw.c \ + libs/video/renderer/vulkan/vulkan_iqm.c \ libs/video/renderer/vulkan/vulkan_lighting.c \ libs/video/renderer/vulkan/vulkan_main.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ @@ -300,6 +301,10 @@ alias_gbuf_src = $(vkshaderpath)/alias_gbuf.frag alias_gbuf_c = $(vkshaderpath)/alias_gbuf.frag.spvc alias_shadow_src = $(vkshaderpath)/alias_shadow.vert alias_shadow_c = $(vkshaderpath)/alias_shadow.vert.spvc +iqmv_src = $(vkshaderpath)/iqm.vert +iqmv_c = $(vkshaderpath)/iqm.vert.spvc +iqmf_src = $(vkshaderpath)/iqm.frag +iqmf_c = $(vkshaderpath)/iqm.frag.spvc passthrough_src = $(vkshaderpath)/passthrough.vert passthrough_c = $(vkshaderpath)/passthrough.vert.spvc fstriangle_src = $(vkshaderpath)/fstriangle.vert @@ -359,6 +364,10 @@ $(alias_gbuf_c): $(alias_gbuf_src) $(alias_shadow_c): $(alias_shadow_src) +$(iqmv_c): $(iqmv_src) + +$(iqmf_c): $(iqmf_src) + $(passthrough_c): $(passthrough_src) $(fstriangle_c): $(fstriangle_src) @@ -395,6 +404,8 @@ vkshader_c = \ $(aliasf_c) \ $(alias_gbuf_c) \ $(alias_shadow_c) \ + $(iqmv_c) \ + $(iqmf_c) \ $(passthrough_c) \ $(fstriangle_c) \ $(pushcolor_c) \ diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 006e61d55..a4a880002 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -44,6 +44,7 @@ #include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_compose.h" #include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_iqm.h" #include "QF/Vulkan/qf_lighting.h" #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_main.h" @@ -560,6 +561,7 @@ vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) static void vulkan_Mod_IQMFinish (model_t *mod) { + Vulkan_Mod_IQMFinish (mod, vulkan_ctx); } static void diff --git a/libs/video/renderer/vulkan/iqm.plist b/libs/video/renderer/vulkan/iqm.plist new file mode 100644 index 000000000..4467d8b89 --- /dev/null +++ b/libs/video/renderer/vulkan/iqm.plist @@ -0,0 +1,254 @@ +{ + setLayouts = { + texture_set = { + bindings = ( + { + binding = 0; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + }; + pipelineLayouts = { + iqm_layout = { + setLayouts = (matrix_set, texture_set); + pushConstantRanges = ( + { + stageFlags = vertex; + offset = 0; + size = "16 * 4 + 4"; + }, + { + stageFlags = fragment; + offset = 68; + size = "3 * 4 + 2 * 4 * 4 + 4"; + }, + ); + }; + }; + + depthStencil = { + test_and_write = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + test_only = { + depthTestEnable = true; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + disable = { + depthTestEnable = false; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + }; + + inputAssembly = { + iqm = { + topology = triangle_list; + primitiveRestartEnable = false; + }; + }; + + vertexInput = { + iqm = { + bindings = ( + { binding = 0; stride = 20; inputRate = vertex; }, + { binding = 1; stride = 40; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32_sfloat; offset = 0; }, // position + { location = 1; binding = 0; format = r8g8b8a8_uint; offset = 0; }, // bonindices + { location = 2; binding = 0; format = r8g8b8a8_unorm; offset = 4; }, // boneweights + + { location = 3; binding = 1; format = r32g32_sfloat; offset = 0; }, // texcoord + { location = 4; binding = 1; format = r32g32b32_sfloat; offset = 8; }, // normal + { location = 5; binding = 1; format = r32g32b32a32_sfloat; offset = 20; }, // tangent + { location = 6; binding = 1; format = r8g8b8a8_unorm; offset = 36; }, // color + + ); + }; + }; + + rasterization = { + cw_cull_back = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + counter_cw_cull_back = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + }; + + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + + attachmentBlendOp = { + disabled = { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }; + alpha_blend = { + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }; + }; + + pipelines = { + iqm_shadow = { + subpass = 0; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/iqm_shadow.vert; + }, + ); + vertexInput = { + bindings = ( + "$properties.vertexInput.iqm.bindings[0]", + "$properties.vertexInput.iqm.bindings[1]", + ); + attributes = ( + "$properties.vertexInput.iqm.attributes[0]", + "$properties.vertexInput.iqm.attributes[1]", + "$properties.vertexInput.iqm.attributes[2]", + "$properties.vertexInput.iqm.attributes[3]", + ); + }; + inputAssembly = $properties.inputAssembly.iqm; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; + colorBlend = $properties.pipelines.iqm_gbuf.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = iqm_layout; + }; + iqm_depth = { + subpass = 0; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/iqm_depth.vert; + }, + ); + vertexInput = { + // depth pass doesn't use UVs + bindings = ( + "$properties.vertexInput.iqm.bindings[0]", + "$properties.vertexInput.iqm.bindings[1]", + ); + attributes = ( + "$properties.vertexInput.iqm.attributes[0]", + "$properties.vertexInput.iqm.attributes[1]", + "$properties.vertexInput.iqm.attributes[2]", + "$properties.vertexInput.iqm.attributes[3]", + ); + }; + inputAssembly = $properties.inputAssembly.iqm; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; + colorBlend = $properties.pipelines.iqm_gbuf.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = iqm_layout; + renderPass = renderpass; + }; + iqm_gbuf = { + subpass = 2; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/iqm.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/iqm_gbuf.frag; + }, + ); + vertexInput = $properties.vertexInput.iqm; + inputAssembly = $properties.inputAssembly.iqm; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ( + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + ); + }; + dynamic = { + dynamicState = ( viewport, scissor, blend_constants ); + }; + layout = iqm_layout; + renderPass = renderpass; + }; + }; +} diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 8cab2d8a6..0f7e19a7b 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -93,6 +93,10 @@ static static #include "libs/video/renderer/vulkan/shader/alias_shadow.vert.spvc" static +#include "libs/video/renderer/vulkan/shader/iqm.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/iqm.frag.spvc" +static #include "libs/video/renderer/vulkan/shader/passthrough.vert.spvc" static #include "libs/video/renderer/vulkan/shader/fstriangle.vert.spvc" @@ -135,6 +139,8 @@ static shaderdata_t builtin_shaders[] = { { "alias.frag", alias_frag, sizeof (alias_frag) }, { "alias_gbuf.frag", alias_gbuf_frag, sizeof (alias_gbuf_frag) }, { "alias_shadow.vert", alias_shadow_vert, sizeof (alias_shadow_vert) }, + { "iqm.vert", iqm_vert, sizeof (iqm_vert) }, + { "iqm.frag", iqm_frag, sizeof (iqm_frag) }, { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, { "fstriangle.vert", fstriangle_vert, sizeof (fstriangle_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, diff --git a/libs/video/renderer/vulkan/shader/iqm.frag b/libs/video/renderer/vulkan/shader/iqm.frag new file mode 100644 index 000000000..7f897422c --- /dev/null +++ b/libs/video/renderer/vulkan/shader/iqm.frag @@ -0,0 +1,44 @@ +#version 450 + +layout (set = 1, binding = 0) uniform sampler2DArray Skin; + +layout (push_constant) uniform PushConstants { + layout (offset = 68) + uint colorA; + uint colorB; + vec4 base_color; + vec4 fog; +}; + +layout (location = 0) in vec2 texcoord; +layout (location = 1) in vec4 position; +layout (location = 2) in vec3 normal; +layout (location = 3) in vec3 tangent; +layout (location = 4) in vec3 bitangent; +layout (location = 5) in vec3 color; + +layout (location = 0) out vec4 frag_color; +layout (location = 1) out vec4 frag_emission; +layout (location = 2) out vec4 frag_normal; +layout (location = 3) out vec4 frag_position; + +void +main (void) +{ + vec4 c; + vec4 e; + vec3 n; + int i; + mat3 tbn = mat3 (tangent, bitangent, normal); + + c = texture (Skin, vec3 (texcoord, 0)) * base_color; + c += texture (Skin, vec3 (texcoord, 1)) * unpackUnorm4x8(colorA); + c += texture (Skin, vec3 (texcoord, 2)) * unpackUnorm4x8(colorB); + e = texture (Skin, vec3 (texcoord, 3)); + n = texture (Skin, vec3 (texcoord, 4)).xyz * 2 - 1; + + frag_color = c; + frag_emission = e; + frag_normal = vec4(tbn * n, 1); + frag_position = position; +} diff --git a/libs/video/renderer/vulkan/shader/iqm.vert b/libs/video/renderer/vulkan/shader/iqm.vert new file mode 100644 index 000000000..590c44118 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/iqm.vert @@ -0,0 +1,52 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection3d; + mat4 View; + mat4 Sky; + mat4 Projection2d; +}; + +layout (set = 3, binding = 0) buffer Bones { + // NOTE these are transposed, so v * m + mat3x4 bones[]; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; + float blend; +}; + +layout (location = 0) in vec3 vposition; +layout (location = 1) in ivec4 vbones; +layout (location = 2) in vec4 vweights; +layout (location = 3) in vec2 vtexcoord; +layout (location = 4) in vec3 vnormal; +layout (location = 5) in vec4 vtangent; +layout (location = 6) in vec4 vcolor; + +layout (location = 0) out vec2 texcoord; +layout (location = 1) out vec4 position; +layout (location = 2) out vec3 normal; +layout (location = 3) out vec3 tangent; +layout (location = 4) out vec3 bitangent; +layout (location = 5) out vec4 color; + +void +main (void) +{ + mat3x4 m = bones[vbones.x] * vweights.x; + m += bones[vbones.y] * vweights.y; + m += bones[vbones.z] * vweights.z; + m += bones[vbones.w] * vweights.w; + vec4 pos = vec4 (Model * vec4(vposition, 1) * m, 1); + gl_Position = Projection3d * (View * pos); + position = pos; + mat3 adjTrans = mat3 (cross(m[1].xyz, m[2].xyz), cross(m[2].xyz, m[0].xyz), + cross(m[0].xyz, m[1].xyz)); + normal = mat3 (Model) * vnormal * adjTrans; + tangent = mat3 (Model) * vtangent.xyz * adjTrans; + bitangent = cross (normal, tangent) * vtangent.w; + texcoord = vtexcoord; + color = vcolor; +} diff --git a/libs/video/renderer/vulkan/vulkan_iqm.c b/libs/video/renderer/vulkan/vulkan_iqm.c new file mode 100644 index 000000000..0e19d4dd6 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_iqm.c @@ -0,0 +1,310 @@ +/* + vulkan_iqm.c + + Vulkan IQM model pipeline + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/5/3 + + 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 + +#include + +#include "QF/cvar.h" +#include "QF/va.h" + +#include "QF/scene/entity.h" + +#include "QF/Vulkan/qf_iqm.h" +#include "QF/Vulkan/qf_matrices.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +typedef struct { + mat4f_t mat; + float blend; + byte colorA[4]; + byte colorB[4]; + vec4f_t base_color; + vec4f_t fog; +} iqm_push_constants_t; + +static const char * __attribute__((used)) iqm_pass_names[] = { + "depth", + "g-buffer", + "translucent", +}; + +static QFV_Subpass subpass_map[] = { + QFV_passDepth, // QFV_iqmDepth + QFV_passGBuffer, // QFV_iqmGBuffer + QFV_passTranslucent, // QFV_iqmTranslucent +}; + +static void +emit_commands (VkCommandBuffer cmd, int pose1, int pose2, + qfv_iqm_skin_t **skins, + uint32_t numPC, qfv_push_constants_t *constants, + iqm_t *iqm, qfv_renderframe_t *rFrame) +{ + vulkan_ctx_t *ctx = rFrame->vulkan_ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + iqmctx_t *ictx = ctx->iqm_context; + + __auto_type mesh = (qfv_iqm_t *) iqm->extra_data; + + VkDeviceSize offsets[] = { 0, 0, }; + VkBuffer buffers[] = { + mesh->geom_buffer, + mesh->rend_buffer, + }; + int bindingCount = skins ? 2 : 1; + + dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0, + VK_INDEX_TYPE_UINT32); + QFV_PushConstants (device, cmd, ictx->layout, numPC, constants); + for (int i = 0; i < iqm->num_meshes; i++) { + if (skins) { + VkDescriptorSet sets[] = { + skins[i]->descriptor, + }; + dfunc->vkCmdBindDescriptorSets (cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, + ictx->layout, 1, 1, sets, 0, 0); + } + dfunc->vkCmdDrawIndexed (cmd, 3 * iqm->meshes[i].num_triangles, 1, + 3 * iqm->meshes[i].first_triangle, 0, 0); + } +} + +void +Vulkan_DrawIQM (entity_t *ent, qfv_renderframe_t *rFrame) +{ + vulkan_ctx_t *ctx = rFrame->vulkan_ctx; + iqmctx_t *ictx = ctx->iqm_context; + iqm_frame_t *aframe = &ictx->frames.a[ctx->curFrame]; + model_t *model = ent->renderer.model; + iqm_t *iqm = (iqm_t *) model->aliashdr; + qfv_iqm_t *mesh = iqm->extra_data; + qfv_iqm_skin_t **skins = &mesh->skins; + iqm_push_constants_t constants = {}; + + constants.blend = R_IQMGetLerpedFrames (ent, iqm); + + qfv_push_constants_t push_constants[] = { + { VK_SHADER_STAGE_VERTEX_BIT, + field_offset (iqm_push_constants_t, mat), + sizeof (mat4f_t), Transform_GetWorldMatrixPtr (ent->transform) }, + { VK_SHADER_STAGE_VERTEX_BIT, + field_offset (iqm_push_constants_t, blend), + sizeof (float), &constants.blend }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (iqm_push_constants_t, colorA), + sizeof (constants.colorA), constants.colorA }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (iqm_push_constants_t, colorB), + sizeof (constants.colorB), constants.colorB }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (iqm_push_constants_t, base_color), + sizeof (constants.base_color), &constants.base_color }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (iqm_push_constants_t, fog), + sizeof (constants.fog), &constants.fog }, + }; + + QuatCopy (ent->renderer.colormod, constants.base_color); + QuatCopy (skins[0]->colora, constants.colorA); + QuatCopy (skins[0]->colorb, constants.colorB); + QuatZero (constants.fog); + + emit_commands (aframe->cmdSet.a[QFV_iqmDepth], + ent->animation.pose1, ent->animation.pose2, + 0, 2, push_constants, iqm, rFrame); + emit_commands (aframe->cmdSet.a[QFV_iqmGBuffer], + ent->animation.pose1, ent->animation.pose2, + skins, 6, push_constants, iqm, rFrame); +} + +static void +alias_begin_subpass (QFV_IQMSubpass subpass, VkPipeline pipeline, + qfv_renderframe_t *rFrame) +{ + vulkan_ctx_t *ctx = rFrame->vulkan_ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + iqmctx_t *ictx = ctx->iqm_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + iqm_frame_t *aframe = &ictx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = aframe->cmdSet.a[subpass]; + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + rFrame->renderpass->renderpass, subpass_map[subpass], + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + QFV_duCmdBeginLabel (device, cmd, va (ctx->va_ctx, "iqm:%s", + iqm_pass_names[subpass]), + { 0.6, 0.5, 0, 1}); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + VkDescriptorSet sets[] = { + Vulkan_Matrix_Descriptors (ctx, ctx->curFrame), + }; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + ictx->layout, 0, 1, sets, 0, 0); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); + + //XXX glsl_Fog_GetColor (fog); + //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; +} + +static void +alias_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + QFV_duCmdEndLabel (device, cmd); + dfunc->vkEndCommandBuffer (cmd); +} + +void +Vulkan_IQMBegin (qfv_renderframe_t *rFrame) +{ + vulkan_ctx_t *ctx = rFrame->vulkan_ctx; + iqmctx_t *ictx = ctx->iqm_context; + iqm_frame_t *aframe = &ictx->frames.a[ctx->curFrame]; + + //XXX quat_t fog; + DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passDepth], + aframe->cmdSet.a[QFV_iqmDepth]); + DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passGBuffer], + aframe->cmdSet.a[QFV_iqmGBuffer]); + + alias_begin_subpass (QFV_iqmDepth, ictx->depth, rFrame); + alias_begin_subpass (QFV_iqmGBuffer, ictx->gbuf, rFrame); +} + +void +Vulkan_IQMEnd (qfv_renderframe_t *rFrame) +{ + vulkan_ctx_t *ctx = rFrame->vulkan_ctx; + iqmctx_t *ictx = ctx->iqm_context; + iqm_frame_t *aframe = &ictx->frames.a[ctx->curFrame]; + + alias_end_subpass (aframe->cmdSet.a[QFV_iqmDepth], ctx); + alias_end_subpass (aframe->cmdSet.a[QFV_iqmGBuffer], ctx); +} + +void +Vulkan_IQMAddSkin (vulkan_ctx_t *ctx, qfv_iqm_skin_t *skin) +{ + iqmctx_t *ictx = ctx->iqm_context; + skin->descriptor = Vulkan_CreateCombinedImageSampler (ctx, skin->view, + ictx->sampler); +} + +void +Vulkan_IQMRemoveSkin (vulkan_ctx_t *ctx, qfv_iqm_skin_t *skin) +{ + Vulkan_FreeTexture (ctx, skin->descriptor); + skin->descriptor = 0; +} + +void +Vulkan_IQM_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + qfvPushDebug (ctx, "iqm init"); + + iqmctx_t *ictx = calloc (1, sizeof (iqmctx_t)); + ctx->iqm_context = ictx; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&ictx->frames, frames); + DARRAY_RESIZE (&ictx->frames, frames); + ictx->frames.grow = 0; + + ictx->depth = Vulkan_CreateGraphicsPipeline (ctx, "alias_depth"); + ictx->gbuf = Vulkan_CreateGraphicsPipeline (ctx, "alias_gbuf"); + ictx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout"); + ictx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler"); + + for (size_t i = 0; i < frames; i++) { + __auto_type aframe = &ictx->frames.a[i]; + + DARRAY_INIT (&aframe->cmdSet, QFV_iqmNumPasses); + DARRAY_RESIZE (&aframe->cmdSet, QFV_iqmNumPasses); + aframe->cmdSet.grow = 0; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &aframe->cmdSet); + + for (int j = 0; j < QFV_iqmNumPasses; j++) { + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + aframe->cmdSet.a[j], + va (ctx->va_ctx, "cmd:iqm:%zd:%s", i, + iqm_pass_names[j])); + } + } + qfvPopDebug (ctx); +} + +void +Vulkan_IQM_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + iqmctx_t *ictx = ctx->iqm_context; + + for (size_t i = 0; i < ictx->frames.size; i++) { + __auto_type aframe = &ictx->frames.a[i]; + free (aframe->cmdSet.a); + } + + dfunc->vkDestroyPipeline (device->dev, ictx->depth, 0); + dfunc->vkDestroyPipeline (device->dev, ictx->gbuf, 0); + free (ictx->frames.a); + free (ictx); +} From ecf33fe8e33f6ae38f0d41a75e1a88cb4fab83c0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:13:18 +0900 Subject: [PATCH 43/77] [model] Add a function to "unload" models The model system is rather clunky as it is focused around caching, so unloading is more of a suggestion than anything, but it was good enough for testing loading and unloading of IQM models in Vulkan. --- include/QF/model.h | 1 + libs/models/model.c | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/include/QF/model.h b/include/QF/model.h index 66628d37c..2489dfb88 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -438,6 +438,7 @@ void Mod_Init_Cvars (void); void Mod_ClearAll (void); model_t *Mod_ForName (const char *name, qboolean crash); void Mod_TouchModel (const char *name); +void Mod_UnloadModel (model_t *model); // brush specific mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); struct set_s *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model); diff --git a/libs/models/model.c b/libs/models/model.c index ee8969543..86e4c7f5b 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -138,22 +138,31 @@ Mod_Init_Cvars (void) Cvar_Register (&gl_textures_external_cvar, 0, 0); } +static void +mod_unload_model (size_t ind) +{ + model_t *mod = mod_known.a[ind]; + + //FIXME this seems to be correct but need to double check the behavior + //with alias models + if (!mod->needload && mod->clear) { + mod->clear (mod, mod->data); + } + if (mod->type != mod_alias) { + mod->needload = true; + } + if (mod->type == mod_sprite) { + mod->cache.data = 0; + } +} + VISIBLE void Mod_ClearAll (void) { size_t i; - model_t **mod; - for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) { - //FIXME this seems to be correct but need to double check the behavior - //with alias models - if (!(*mod)->needload && (*mod)->clear) { - (*mod)->clear (*mod, (*mod)->data); - } - if ((*mod)->type != mod_alias) - (*mod)->needload = true; - if ((*mod)->type == mod_sprite) - (*mod)->cache.data = 0; + for (i = 0; i < mod_numknown; i++) { + mod_unload_model (i); } } @@ -323,6 +332,16 @@ Mod_TouchModel (const char *name) } } +VISIBLE void +Mod_UnloadModel (model_t *model) +{ + for (size_t i = 0; i < mod_numknown; i++) { + if (mod_known.a[i] == model) { + mod_unload_model (i); + } + } +} + VISIBLE void Mod_Print (void) { From 3de10f32c7cddb7d508e86acec0d1c50d94eaa8e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:15:45 +0900 Subject: [PATCH 44/77] [ruamoko] Add builtins for handling models Just "loading" and "unloading" (both really just hints due to the caching system), and an internal function for converting a handle to a model pointer, but it let me test IQM loading and unloading in Vulkan. --- include/rua_internal.h | 2 + libs/ruamoko/Makemodule.am | 1 + libs/ruamoko/rua_game_init.c | 1 + libs/ruamoko/rua_model.c | 179 +++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 libs/ruamoko/rua_model.c diff --git a/include/rua_internal.h b/include/rua_internal.h index b58eb4530..80f97003a 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -62,6 +62,8 @@ struct plitem_s *Plist_GetItem (struct progs_s *pr, int handle); void RUA_Input_Init (struct progs_s *pr, int secure); void RUA_Mersenne_Init (struct progs_s *pr, int secure); +void RUA_Model_Init (struct progs_s *pr, int secure); +struct model_s *Model_GetModel (progs_t *pr, int handle); void RUA_Scene_Init (struct progs_s *pr, int secure); #endif//__rua_internal_h diff --git a/libs/ruamoko/Makemodule.am b/libs/ruamoko/Makemodule.am index 118fde38c..c34590426 100644 --- a/libs/ruamoko/Makemodule.am +++ b/libs/ruamoko/Makemodule.am @@ -38,4 +38,5 @@ libs_ruamoko_libQFruamoko_client_la_SOURCES= \ libs/ruamoko/rua_game_init.c \ libs/ruamoko/rua_input.c \ libs/ruamoko/rua_mersenne.c \ + libs/ruamoko/rua_model.c \ libs/ruamoko/rua_scene.c diff --git a/libs/ruamoko/rua_game_init.c b/libs/ruamoko/rua_game_init.c index ac1628cc8..1312d7ee3 100644 --- a/libs/ruamoko/rua_game_init.c +++ b/libs/ruamoko/rua_game_init.c @@ -36,6 +36,7 @@ static void (*init_funcs[])(progs_t *, int) = { RUA_Input_Init, RUA_Mersenne_Init, + RUA_Model_Init, RUA_Scene_Init, }; diff --git a/libs/ruamoko/rua_model.c b/libs/ruamoko/rua_model.c new file mode 100644 index 000000000..e021ba9d5 --- /dev/null +++ b/libs/ruamoko/rua_model.c @@ -0,0 +1,179 @@ +/* + bi_model.c + + Ruamkoko model builtins + + Copyright (C) 2022 Bill Currie + + 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 + +#include +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/model.h" +#include "QF/progs.h" + +#include "rua_internal.h" + +typedef struct rua_model_s { + struct rua_model_s *next; + struct rua_model_s **prev; + model_t *model; +} rua_model_t; + +typedef struct { + PR_RESMAP (rua_model_t) model_map; + rua_model_t *handles; + progs_t *pr; +} rua_model_resources_t; + +static rua_model_t * +rua_model_handle_new (rua_model_resources_t *res) +{ + return PR_RESNEW (res->model_map); +} + +static void +rua_model_handle_free (rua_model_resources_t *res, rua_model_t *handle) +{ + PR_RESFREE (res->model_map, handle); +} + +static void +rua_model_handle_reset (rua_model_resources_t *res) +{ + PR_RESRESET (res->model_map); +} + +static inline rua_model_t * __attribute__((pure)) +rua__model_handle_get (rua_model_resources_t *res, int index, const char *name) +{ + rua_model_t *handle = 0; + + handle = PR_RESGET(res->model_map, index); + if (!handle) { + PR_RunError (res->pr, "invalid model handle passed to %s", name + 3); + } + return handle; +} +#define rua_model_handle_get(res, index) \ + rua__model_handle_get (res, index, __FUNCTION__) + +static inline int __attribute__((pure)) +rua_model_handle_index (rua_model_resources_t *res, rua_model_t *handle) +{ + return PR_RESINDEX(res->model_map, handle); +} + +static void +bi_rua_model_clear (progs_t *pr, void *_res) +{ + rua_model_resources_t *res = (rua_model_resources_t *) _res; + rua_model_t *handle; + + for (handle = res->handles; handle; handle = handle->next) + Mod_UnloadModel (handle->model); + res->handles = 0; + rua_model_handle_reset (res); +} + +static int +alloc_handle (rua_model_resources_t *res, model_t *model) +{ + rua_model_t *handle = rua_model_handle_new (res); + + if (!handle) + return 0; + + handle->next = res->handles; + handle->prev = &res->handles; + if (res->handles) + res->handles->prev = &handle->next; + res->handles = handle; + handle->model = model; + return rua_model_handle_index (res, handle); +} + +static void +bi_Model_Load (progs_t *pr, void *_res) +{ + __auto_type res = (rua_model_resources_t *) _res; + const char *path = P_GSTRING (pr, 0); + model_t *model; + + R_INT (pr) = 0; + if (!(model = Mod_ForName (path, 0))) + return; + if (!(R_INT (pr) = alloc_handle (res, model))) + Mod_UnloadModel (model); +} + +model_t * +Model_GetModel (progs_t *pr, int handle) +{ + rua_model_resources_t *res = PR_Resources_Find (pr, "Model"); + rua_model_t *h = rua_model_handle_get (res, handle); + + return h->model; +} + +static void +bi_Model_Unload (progs_t *pr, void *_res) +{ + __auto_type res = (rua_model_resources_t *) _res; + int handle = P_INT (pr, 0); + rua_model_t *h = rua_model_handle_get (res, handle); + + if (!h) + PR_RunError (pr, "invalid model handle passed to Qclose"); + Mod_UnloadModel (h->model); + *h->prev = h->next; + if (h->next) + h->next->prev = h->prev; + rua_model_handle_free (res, h); +} + +#define bi(x,np,params...) {#x, bi_##x, -1, np, {params}} +#define p(type) PR_PARAM(type) +#define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), } +static builtin_t builtins[] = { + bi(Model_Load, 1, p(string)), + bi(Model_Unload, 1, p(ptr)), + {0} +}; + +void +RUA_Model_Init (progs_t *pr, int secure) +{ + rua_model_resources_t *res = calloc (sizeof (rua_model_resources_t), 1); + res->pr = pr; + + PR_Resources_Register (pr, "Model", res, bi_rua_model_clear); + PR_RegisterBuiltins (pr, builtins, res); +} From 0983cc5d8c41f0a2973cb17d026f1d89c0b8762d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:17:19 +0900 Subject: [PATCH 45/77] [scene] Fix a spelling error in a comment --- libs/scene/hierarchy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/scene/hierarchy.c b/libs/scene/hierarchy.c index 3aa758624..c6b6f7074 100644 --- a/libs/scene/hierarchy.c +++ b/libs/scene/hierarchy.c @@ -80,7 +80,7 @@ hierarchy_calcLocalInverse (hierarchy_t *h, uint32_t index) vec4f_t t = h->localMatrix.a[index][3]; // "one" is to ensure both the scalar and translation have 1 in their - // forth components + // fourth components vec4f_t one = { 0, 0, 0, 1 }; vec4f_t nx = { x[0], y[0], z[0], 0 }; vec4f_t ny = { x[1], y[1], z[1], 0 }; From c10e529dfd95a5745602b351093b1f97ef051bed Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:18:05 +0900 Subject: [PATCH 46/77] [vulkan] Clean up alias pipeline layout spec It didn't really need the extra layer of indirection: now it's much clearer that the alias pipeline uses matrices and textures. --- libs/video/renderer/vulkan/qfpipeline.plist | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 876613b98..ce3a7dcff 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -206,8 +206,6 @@ }, ); }; - quakebsp_set = $properties.setLayouts.texture_set; - alias_set = $properties.setLayouts.texture_set; sprite_set = { bindings = ( { @@ -337,7 +335,7 @@ ); }; alias_layout = { - setLayouts = (matrix_set, alias_set); + setLayouts = (matrix_set, texture_set); pushConstantRanges = ( { stageFlags = vertex; From e95d498b974a510de7dce102c8c524905e056199 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:28:20 +0900 Subject: [PATCH 47/77] [vulkan] Resurrect the forward render pass spec It's not used yet, and thus may have some incorrect settings, but I decided that I will probably want it at some stage for qwaq. It's essentially was was in the original spec, but updated for some of the niceties added to parsing since I removed it back then. It's also in its own file. --- libs/video/renderer/vulkan/forward.plist | 199 +++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 libs/video/renderer/vulkan/forward.plist diff --git a/libs/video/renderer/vulkan/forward.plist b/libs/video/renderer/vulkan/forward.plist new file mode 100644 index 000000000..e8c703a23 --- /dev/null +++ b/libs/video/renderer/vulkan/forward.plist @@ -0,0 +1,199 @@ +{ + flat_color_image_template = { + imageType = `2d; + samples = $msaaSamples; + extent = { + width = $output.extent.width; + height = $output.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|transient_attachment; + }; + images = { + depth = { + @inherit = @properties.flat_color_image_template; + format = x8_d24_unorm_pack32; + usage = depth_stencil_attachment|transient_attachment; + }; + color = { + @inherit = @properties.flat_color_image_template; + format = $output.format; + }; + }; + flat_color_view_template = { + viewType = `2d; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + imageViews = { + depth = { + @inherit = $properties.flat_color_view_template; + image = depth; + format = $properties.images.depth.format; + subresourceRange = { + aspectMask = depth; + }; + }; + color = { + @inherit = $properties.flat_color_view_template; + image = color; + format = $properties.images.color.format; + }; + }; + framebuffer = { + renderPass = $properties.renderpass; + attachment = ($output.view, depth); + width = $output.extent.width; + height = $output.extent.height; + layers = 1; + }; + framebuffer_msaa = { + renderPass = $properties.renderpass_msaa; + attachment = ($output.view, depth, color); + width = $output.extent.width; + height = $output.extent.height; + layers = 1; + }; + attachment_template = { + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }; + renderpass = { + attachments = ( + { + @inherit = $properties.attachment_template; + format = $output.format; + loadOp = clear; + storeOp = store; + finalLayout = present_src_khr; + }, + { + @inherit = $properties.attachment_template; + format = $properties.images.depth.format; + loadOp = clear; + finalLayout = depth_stencil_attachment_optimal; + }, + ); + subpasses = ( + { + pipelineBindPoint = graphics; + colorAttachments = ( + { + attachment = 0; + layout = color_attachment_optimal; + } + ); + depthStencilAttachment = { + attachment = 1; + layout = depth_stencil_attachment_optimal; + }; + preserveAttachments = (); + }, + ); + dependencies = ( + { + srcSubpass = ~0u; // external + dstSubpass = 0; + srcStageMask = top_of_pipe; + dstStageMask = color_attachment_output; + srcAccessMask = memory_read; + dstAccessMask = color_attachment_write; + dependencyFlags = by_region; + }, + { + srcSubpass = 0; + dstSubpass = ~0u; // external + srcStageMask = color_attachment_output; + dstStageMask = bottom_of_pipe; + srcAccessMask = color_attachment_write; + dstAccessMask = memory_read; + dependencyFlags = by_region; + }, + ); + }; + renderpass_msaa = { + attachments = ( + { + @inherit = $properties.attachment_template; + format = $output.format; + storeOp = store; + finalLayout = present_src_khr; + }, + { + @inherit = $properties.attachment_template; + format = $properties.images.depth.format; + samples = $msaaSamples; + loadOp = clear; + storeOp = dont_care; + finalLayout = depth_stencil_attachment_optimal; + }, + { + @inherit = $properties.attachment_template; + format = $swapchain.format; + samples = $msaaSamples; + loadOp = clear; + storeOp = store;// dont_care? + finalLayout = color_attachment_optimal; + }, + ); + subpasses = ( + { + pipelineBindPoint = graphics; + colorAttachments = ( + { + attachment = 2; + layout = color_attachment_optimal; + } + ); + resolveAttachments = ( + { + attachment = 0; + layout = color_attachment_optimal; + } + ); + depthStencilAttachment = { + attachment = 1; + layout = depth_stencil_attachment_optimal; + }; + preserveAttachments = (); + }, + ); + dependencies = ( + { + srcSubpass = ~0u; // external + dstSubpass = 0; + srcStageMask = top_of_pipe; + dstStageMask = color_attachment_output; + srcAccessMask = memory_read; + dstAccessMask = color_attachment_write; + dependencyFlags = by_region; + }, + { + srcSubpass = 0; + dstSubpass = ~0u; // external + srcStageMask = color_attachment_output; + dstStageMask = bottom_of_pipe; + srcAccessMask = color_attachment_write; + dstAccessMask = memory_read; + dependencyFlags = by_region; + }, + ); + }; +} From 2d75a652f100d4da13a18da1f789b1c159d76fff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:36:14 +0900 Subject: [PATCH 48/77] [vulkan] Remove a dead file I guess I forgot to delete draw.h when I added qf_draw.h. --- include/QF/Makemodule.am | 1 - include/QF/Vulkan/draw.h | 237 --------------------------------------- 2 files changed, 238 deletions(-) delete mode 100644 include/QF/Vulkan/draw.h diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index b18a43f55..c9783b4fa 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -178,7 +178,6 @@ include_qf_vulkan = \ include/QF/Vulkan/debug.h \ include/QF/Vulkan/descriptor.h \ include/QF/Vulkan/device.h \ - include/QF/Vulkan/draw.h \ include/QF/Vulkan/funclist.h \ include/QF/Vulkan/image.h \ include/QF/Vulkan/instance.h \ diff --git a/include/QF/Vulkan/draw.h b/include/QF/Vulkan/draw.h deleted file mode 100644 index 8f6b78889..000000000 --- a/include/QF/Vulkan/draw.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - draw.h - - Video buffer handling definitions and prototypes - - Copyright (C) 1996-1997 Id Software, Inc. - - 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 - -*/ - -#ifndef __QF_draw_h -#define __QF_draw_h - -/** \defgroup video Video Sub-sytem */ - -/** \defgroup video_renderer Renderer Sub-system - \ingroup video -*/ - -/** \defgroup video_renderer_draw Generic draw functions - \ingroup video_renderer -*/ -///@{ - -#include "QF/wad.h" - -extern byte *draw_chars; - -/** Initialize the draw stuff. -*/ -void Draw_Init (void); - -/** Draws one 8*8 graphics character with 0 being transparent. - It can be clipped to the top of the screen to allow the console to be - smoothly scrolled off. - \param x horizontal location of the top left corner of the character. - \param y vertical location of the top left corner of the character. - \param ch 8 bit character to draw. - \note The character drawn is from the quake character set, which is - (by default) standard ascii for 0x20-0x7e (white). 0xa0-0xfe is - also standard ascii (brown). 0x01-0x1f and 0x80-0x9f are - various drawing characters, and 0x7f is a backwards arrow. -*/ -void Draw_Character (int x, int y, unsigned ch); - -/** Draws a character string to the screen. - No line wrapping is performed. - \param x horizontal location of the top left corner of the character. - \param y vertical location of the top left corner of the character. - \param str 8 bit character string to draw. - \note See Draw_Character() for character set description. - String is normal nul terminated C string. -*/ -void Draw_String (int x, int y, const char *str); - -/** Draws a character sub-string to the screen. - No line wrapping is performed. - \param x horizontal location of the top left corner of the character. - \param y vertical location of the top left corner of the character. - \param str 8 bit character string to draw. - \param count Maximum characters of the string to draw. - \note See Draw_Character() for character set description. - Draws up to \p count characters, or stops at the first nul - character. -*/ -void Draw_nString (int x, int y, const char *str, int count); - -/** Draws a character string to the screen. - No line wrapping is performed. - \param x horizontal location of the top left corner of the character. - \param y vertical location of the top left corner of the character. - \param str 8 bit character string to draw. - \note See Draw_Character() for character set description. - String is normal nul terminated C string. - Characters of the string are forced to have their high bit set - (ie, they will be in the range 0x80-0xff). -*/ -void Draw_AltString (int x, int y, const char *str); - -/** Draw the console background with various optional effects. - \param lines Vertical size in pixels of the console. - \param alpha Console transparency level (255 = opaque). - \note \p alpha is effective only in the OpenGL renderer. Effectively - 255 (opaque) for the software renderer. - - \c gl_conspin causes the background to spin. - - \c gl_constretch causes the background to stretch rather than slide. -*/ -void Draw_ConsoleBackground (int lines, byte alpha); - -/** Draw a crosshair at the center of the screen. - \c crosshair specifies which crosshair (1 = '+', 2 = large 'x' shape, - 3 = fancy '+' shape) - \c cl_crossx and \c cl_crossy offset the crosshair from the center of the - screen. -*/ -void Draw_Crosshair (void); - -/** Draw the specified crosshair on the screen. - \param ch crosshair to draw - \param x horizontal position of the center of the crosshair. - \param y vertical position of the center of the crosshair. - - See Draw_Crosshair() for description of crosshair values. -*/ -void Draw_CrosshairAt (int ch, int x, int y); - -/** Clear a rectangle with a tiled background. - \param x horizontal position of the upper left corner of the rectangle - \param y horizontal position of the upper left corner of the rectangle - \param w width of the rectangle - \param h height of the rectangle - - The background used is the "backtile" WAD lump. -*/ -void Draw_TileClear (int x, int y, int w, int h); - -/** Clear a rectangle with a solid color. - \param x horizontal position of the upper left corner of the rectangle - \param y horizontal position of the upper left corner of the rectangle - \param w width of the rectangle - \param h height of the rectangle - \param c 8 bit color index. - - The color comes from the quake palette. -*/ -void Draw_Fill (int x, int y, int w, int h, int c); - -/** Draw a text box on the screen - \param x horizontal location of the upper left corner of the box - \param y vertical location of the upper left corner of the box - \param width horizontal size in character cells of the region - \param lines vertical size in character cells of the region - \param alpha transparency of the box -*/ -void Draw_TextBox (int x, int y, int width, int lines, byte alpha); - -/** Darken the screen. -*/ -void Draw_FadeScreen (void); - -/** Shift the screen colors. -*/ -void Draw_BlendScreen (quat_t color); -///@} - -/** \defgroup video_renderer_draw_qpic QPic functions - \ingroup video_renderer_draw -*/ -///@{ -/** Load a qpic from the filesystem. - \param path path of the file within the quake filesystem - \param alpha transparency level of the pic. - \return pointer qpic data. - \note Up to MAX_CACHED_PICS qpics can be loaded at a time this way -*/ -qpic_t *Draw_CachePic (const char *path, qboolean alpha); - -/** Remove a qpic from the qpic cache. - - This affects only those qpics that were loaded via Draw_CachePic. - - \param path path of the file within the quake filesystem -*/ -void Draw_UncachePic (const char *path); - -/** Create a qpic from raw data. - - \param width The width of the pic. - \param height The height of the pic. - \param data The raw data bytes. The system palette will be used for - colors. - \return pointer qpic data. -*/ -qpic_t *Draw_MakePic (int width, int height, const byte *data); - -/** Destroy a qpic created by Draw_MakePic. - - \param pic The qpic to destory. -*/ -void Draw_DestroyPic (qpic_t *pic); - -/** Load a qpic from gfx.wad. - \param name name of the was lump to load - \return pointer qpic data. -*/ -qpic_t *Draw_PicFromWad (const char *name); - -/** Draw a qpic to the screen - \param x horizontal location of the upper left corner of the qpic - \param y vertical location of the upper left corner of the qpic - \param pic qpic to draw -*/ -void Draw_Pic (int x, int y, qpic_t *pic); - -/** Draw a qpic to the screen - \param x horizontal location of the upper left corner of the qpic - \param y vertical location of the upper left corner of the qpic - \param pic qpic to draw -*/ -void Draw_Picf (float x, float y, qpic_t *pic); - -/** Draw a sub-region of a qpic to the screan - \param x horizontal screen location of the upper left corner of the - sub-region - \param y vertical screen location of the upper left corner of the - sub-region - \param pic qpic to draw - \param srcx horizontal qpic location of the upper left corner of the - sub-region - \param srcy vertical qpic location of the upper left corner of the - sub-region - \param width horizontal size of the sub-region to be drawn - \param height vertical size of the sub-region to be drawn -*/ -void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); -///@} - -#endif//__QF_draw_h From 8e658eac7801cf9ef0bd6e57dfbedf138fd1c669 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:39:47 +0900 Subject: [PATCH 49/77] [vulkan] Correct a pile of copyright attributions Id Software had pretty much nothing to do with the vulkan renderer (they still get credit for code that's heavily based on the original quake code, of course). --- include/QF/Vulkan/qf_vid.h | 2 +- libs/video/renderer/vid_render_vulkan.c | 3 +-- libs/video/renderer/vulkan/buffer.c | 1 - libs/video/renderer/vulkan/capture.c | 1 - libs/video/renderer/vulkan/command.c | 1 - libs/video/renderer/vulkan/descriptor.c | 1 - libs/video/renderer/vulkan/device.c | 1 - libs/video/renderer/vulkan/image.c | 1 - libs/video/renderer/vulkan/memory.c | 1 - libs/video/renderer/vulkan/pipeline.c | 1 - libs/video/renderer/vulkan/renderpass.c | 1 - 11 files changed, 2 insertions(+), 12 deletions(-) diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index bf76b13d2..6f235d1b6 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -3,7 +3,7 @@ vulkan vid stuff from the renderer. - Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2019 Bill Currie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a4a880002..424363571 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -771,8 +771,7 @@ static plugin_t plugin_info = { QFPLUGIN_VERSION, "0.1", "Vulkan Renderer", - "Copyright (C) 1996-1997 Id Software, Inc.\n" - "Copyright (C) 1999-2019 contributors of the QuakeForge project\n" + "Copyright (C) 2019 Bill Currie \n" "Please see the file \"AUTHORS\" for a list of contributors", &plugin_info_funcs, &plugin_info_data, diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c index 729fe914d..30030adee 100644 --- a/libs/video/renderer/vulkan/buffer.c +++ b/libs/video/renderer/vulkan/buffer.c @@ -3,7 +3,6 @@ Vulkan buffer functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/capture.c b/libs/video/renderer/vulkan/capture.c index d11ea7ad9..974957aa7 100644 --- a/libs/video/renderer/vulkan/capture.c +++ b/libs/video/renderer/vulkan/capture.c @@ -3,7 +3,6 @@ Vulkan frame capture support - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2021 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 0dae2bc5e..c35fede96 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -3,7 +3,6 @@ Common Vulkan video driver functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2019 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c index 356fa5f40..026d5ae9c 100644 --- a/libs/video/renderer/vulkan/descriptor.c +++ b/libs/video/renderer/vulkan/descriptor.c @@ -3,7 +3,6 @@ Vulkan descriptor functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 6f632ef34..0ff989511 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -3,7 +3,6 @@ Common Vulkan video driver functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2019 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 27bb3cf7b..62daaaf38 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -3,7 +3,6 @@ Vulkan image functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/memory.c b/libs/video/renderer/vulkan/memory.c index dbcc81de6..ee2d6ec01 100644 --- a/libs/video/renderer/vulkan/memory.c +++ b/libs/video/renderer/vulkan/memory.c @@ -3,7 +3,6 @@ Vulkan memory functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index 5130a55c2..b602287f6 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -3,7 +3,6 @@ Vulkan pipeline functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index ead9a7363..e0a95db8d 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -3,7 +3,6 @@ Vulkan render pass and frame buffer functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie This program is free software; you can redistribute it and/or From 3b926ec154e3ec157647e6653bacbc6a120f036e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 14:42:50 +0900 Subject: [PATCH 50/77] [io_mesh_qfmdl] Update plist parsing for ` This gets it pretty much in line with the C implementation. Certainly good enough for validating a render pass spec :) --- tools/io_mesh_qfmdl/qfplist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/io_mesh_qfmdl/qfplist.py b/tools/io_mesh_qfmdl/qfplist.py index 4f16a2c34..7e5ffc762 100644 --- a/tools/io_mesh_qfmdl/qfplist.py +++ b/tools/io_mesh_qfmdl/qfplist.py @@ -20,7 +20,7 @@ # quotables = ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - + "abcdefghijklmnopqrstuvwxyz!#$%&*+-./:?@|~_^") + + "`abcdefghijklmnopqrstuvwxyz!#$%&*+-./:?@|~_^") class PListError(Exception): def __init__(self, line, message): From 2493ca71c7257143e640c9c7d9c4974db9b6a427 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 17:38:38 +0900 Subject: [PATCH 51/77] [ruamoko] Allow entity model to be set And add header and function definitions for scene to libcsqc. --- libs/ruamoko/rua_model.c | 3 ++ libs/ruamoko/rua_scene.c | 19 ++++++++++++ ruamoko/include/Makemodule.am | 3 +- ruamoko/include/scene.h | 54 +++++++++++++++++++++++++++++++++++ ruamoko/lib/Makemodule.am | 1 + ruamoko/lib/scene.r | 40 ++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 ruamoko/include/scene.h create mode 100644 ruamoko/lib/scene.r diff --git a/libs/ruamoko/rua_model.c b/libs/ruamoko/rua_model.c index e021ba9d5..4f8d5b8c0 100644 --- a/libs/ruamoko/rua_model.c +++ b/libs/ruamoko/rua_model.c @@ -137,6 +137,9 @@ bi_Model_Load (progs_t *pr, void *_res) model_t * Model_GetModel (progs_t *pr, int handle) { + if (!handle) { + return 0; + } rua_model_resources_t *res = PR_Resources_Find (pr, "Model"); rua_model_t *h = rua_model_handle_get (res, handle); diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index d43a4da7b..1c577d6fd 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -38,7 +38,11 @@ #include "QF/cmem.h" #include "QF/hash.h" +#include "QF/model.h" #include "QF/progs.h" +#include "QF/render.h" + +#include "QF/plugin/vid_render.h" #include "QF/scene/entity.h" #include "QF/scene/scene.h" @@ -209,6 +213,20 @@ bi_Entity_GetTransform (progs_t *pr, void *_res) R_ULONG (pr) = MAKE_ID (ent->transform->id, ent_id); } +static void +bi_Entity_SetModel (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + pr_ulong_t ent_id = P_ULONG (pr, 0); + pr_int_t model_id = P_INT (pr, 1); + entity_t *ent = rua_entity_get (res, ent_id); + model_t *model = Model_GetModel (pr, model_id); + + R_RemoveEfrags (ent); + ent->renderer.model = model; + R_AddEfrags (&r_data->refdef->worldmodel->brush, ent);//FIXME r_data +} + static void bi_Transform_ChildCount (progs_t *pr, void *_res) { @@ -431,6 +449,7 @@ static builtin_t builtins[] = { bi(Scene_DestroyEntity, 1, p(ulong)), bi(Entity_GetTransform, 1, p(ulong)), + bi(Entity_SetModel, 2, p(ulong), p(int)), bi(Transform_ChildCount, 1, p(ulong)), bi(Transform_GetChild, 2, p(ulong), p(int)), diff --git a/ruamoko/include/Makemodule.am b/ruamoko/include/Makemodule.am index 800c8ba89..8d19564d0 100644 --- a/ruamoko/include/Makemodule.am +++ b/ruamoko/include/Makemodule.am @@ -16,8 +16,9 @@ ruamoko_include = \ ruamoko/include/qw_physics.h \ ruamoko/include/qw_sys.h \ ruamoko/include/server.h \ - ruamoko/include/sound.h \ + ruamoko/include/scene.h \ ruamoko/include/script.h \ + ruamoko/include/sound.h \ ruamoko/include/stdlib.h \ ruamoko/include/string.h \ ruamoko/include/sv_sound.h \ diff --git a/ruamoko/include/scene.h b/ruamoko/include/scene.h new file mode 100644 index 000000000..cf66b5d82 --- /dev/null +++ b/ruamoko/include/scene.h @@ -0,0 +1,54 @@ +#ifndef __ruamoko_scene_h +#define __ruamoko_scene_h + +//FIXME this should be a native type so it can be used in math +typedef struct { + vec4 col[4]; +} mat4x4; + +//FIXME need a handle type +typedef struct { long handle; } scene_t; +typedef struct { long handle; } entity_t; +typedef struct { long handle; } transform_t; +typedef struct { int handle; } model_t; + +scene_t Scene_NewScene (void); +void Scene_DeleteScene (scene_t scene); +entity_t Scene_CreateEntity (scene_t scene); +void Scene_DestroyEntity (entity_t ent); + +transform_t Entity_GetTransform (entity_t ent); +void Entity_SetModel (entity_t ent, model_t model); + +unsigned Transform_ChildCount (transform_t transform); +transform_t Transform_GetChild (transform_t transform, + unsigned childIndex); +void Transform_SetParent (transform_t transform, transform_t parent); +transform_t Transform_GetParent (transform_t transform); +void Transform_SetTag (transform_t transform, unsigned tag); +unsigned Transform_GetTag (transform_t transform); +mat4x4 Transform_GetLocalMatrix (transform_t transform); +mat4x4 Transform_GetLocalInverse (transform_t transform); +mat4x4 Transform_GetWorldMatrix (transform_t transform); +mat4x4 Transform_GetWorldInverse (transform_t transform); +vec4 Transform_GetLocalPosition (transform_t transform); +void Transform_SetLocalPosition (transform_t transform, vec4 position); +vec4 Transform_GetLocalRotation (transform_t transform); +void Transform_SetLocalRotation (transform_t transform, vec4 rotation); +vec4 Transform_GetLocalScale (transform_t transform); +void Transform_SetLocalScale (transform_t transform, vec4 scale); +vec4 Transform_GetWorldPosition (transform_t transform); +void Transform_SetWorldPosition (transform_t transform, vec4 position); +vec4 Transform_GetWorldRotation (transform_t transform); +void Transform_SetWorldRotation (transform_t transform, vec4 rotation); +vec4 Transform_GetWorldScale (transform_t transform); +void Transform_SetLocalTransform (transform_t transform, vec4 scale, + vec4 rotation, vec4 position); +vec4 Transform_Forward (transform_t transform); +vec4 Transform_Right (transform_t transform); +vec4 Transform_Up (transform_t transform); + +model_t Model_Load (string path); +void Model_Unload (model_t model); + +#endif//__ruamoko_scene_h diff --git a/ruamoko/lib/Makemodule.am b/ruamoko/lib/Makemodule.am index 3f879d6e9..2528d5d40 100644 --- a/ruamoko/lib/Makemodule.am +++ b/ruamoko/lib/Makemodule.am @@ -65,6 +65,7 @@ ruamoko_lib_libcsqc_a_src= \ ruamoko/lib/gib.r \ ruamoko/lib/input.r \ ruamoko/lib/mersenne.r \ + ruamoko/lib/scene.r \ ruamoko/lib/key.r ruamoko_lib_common_dep=$(call qcautodep,$(ruamoko_lib_common_src)) diff --git a/ruamoko/lib/scene.r b/ruamoko/lib/scene.r new file mode 100644 index 000000000..6bcf931ed --- /dev/null +++ b/ruamoko/lib/scene.r @@ -0,0 +1,40 @@ +#include + +scene_t Scene_NewScene (void) = #0; +void Scene_DeleteScene (scene_t scene) = #0; +entity_t Scene_CreateEntity (scene_t scene) = #0; +void Scene_DestroyEntity (entity_t ent) = #0; + +transform_t Entity_GetTransform (entity_t ent) = #0; +void Entity_SetModel (entity_t ent, model_t model) = #0; + +unsigned Transform_ChildCount (transform_t transform) = #0; +transform_t Transform_GetChild (transform_t transform, + unsigned childIndex) = #0; +void Transform_SetParent (transform_t transform, transform_t parent) = #0; +transform_t Transform_GetParent (transform_t transform) = #0; +void Transform_SetTag (transform_t transform, unsigned tag) = #0; +unsigned Transform_GetTag (transform_t transform) = #0; +mat4x4 Transform_GetLocalMatrix (transform_t transform) = #0; +mat4x4 Transform_GetLocalInverse (transform_t transform) = #0; +mat4x4 Transform_GetWorldMatrix (transform_t transform) = #0; +mat4x4 Transform_GetWorldInverse (transform_t transform) = #0; +vec4 Transform_GetLocalPosition (transform_t transform) = #0; +void Transform_SetLocalPosition (transform_t transform, vec4 position) = #0; +vec4 Transform_GetLocalRotation (transform_t transform) = #0; +void Transform_SetLocalRotation (transform_t transform, vec4 rotation) = #0; +vec4 Transform_GetLocalScale (transform_t transform) = #0; +void Transform_SetLocalScale (transform_t transform, vec4 scale) = #0; +vec4 Transform_GetWorldPosition (transform_t transform) = #0; +void Transform_SetWorldPosition (transform_t transform, vec4 position) = #0; +vec4 Transform_GetWorldRotation (transform_t transform) = #0; +void Transform_SetWorldRotation (transform_t transform, vec4 rotation) = #0; +vec4 Transform_GetWorldScale (transform_t transform) = #0; +void Transform_SetLocalTransform (transform_t transform, vec4 scale, + vec4 rotation, vec4 position) = #0; +vec4 Transform_Forward (transform_t transform) = #0; +vec4 Transform_Right (transform_t transform) = #0; +vec4 Transform_Up (transform_t transform) = #0; + +model_t Model_Load (string path) = #0; +void Model_Unload (model_t model) = #0; From eaaa0f597f091b488d560688d12461ce61c521c7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 18:00:35 +0900 Subject: [PATCH 52/77] [scene] Set the color for new entities Black doesn't show up too well on black. Really, this isn't the best fix, but it will do until I can rework entities to use a component system. --- libs/scene/scene.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/scene/scene.c b/libs/scene/scene.c index e08fb718c..13742f2a9 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -35,6 +35,7 @@ # include #endif +#include "QF/mathlib.h" #include "QF/progs.h" // for PR_RESMAP #include "QF/sys.h" @@ -84,6 +85,8 @@ Scene_CreateEntity (scene_t *scene) hierarchy_t *h = ent->transform->hierarchy; h->entity.a[ent->transform->index] = ent; + QuatSet (1, 1, 1, 1, ent->renderer.colormod); + return ent; } From fe63d93e8ec698c8abaf17114fb788cc3ae82f74 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 18:01:50 +0900 Subject: [PATCH 53/77] [build] Remove some csqc dependencies vkgen and the programs in ruamoko/qwaq just don't need it. --- libs/video/renderer/vulkan/vkgen/Makemodule.am | 4 ++-- ruamoko/qwaq/Makemodule.am | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 39c73f081..a1a0099b1 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -26,8 +26,8 @@ VKGENFLAGS = -I$(top_srcdir)/libs/video/renderer/vulkan/vkgen -I$(VKGENUSRINC) vkgen_dat_SOURCES=$(vkgen_dat_src) vkgen_obj=$(vkgen_dat_SOURCES:.r=.o) vkgen_dep=$(call qcautodep,$(vkgen_dat_SOURCES:.o=.Qo)) -vkgen.dat$(EXEEXT): $(vkgen_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(V_QFCCLD)$(QLINK) -o $@ $(vkgen_obj) -lcsqc -lr +vkgen.dat$(EXEEXT): $(vkgen_obj) $(QFCC_DEP) ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(vkgen_obj) -lr include $(vkgen_dep) # am--include-marker r_depfiles_remade += $(vkgen_dep) diff --git a/ruamoko/qwaq/Makemodule.am b/ruamoko/qwaq/Makemodule.am index 6cbf62829..cd278606b 100644 --- a/ruamoko/qwaq/Makemodule.am +++ b/ruamoko/qwaq/Makemodule.am @@ -126,32 +126,32 @@ ruamoko_qwaq_qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) ruamoko_qwaq_qwaq_app_dat_SOURCES=$(qwaq_app_dat_src) ruamoko_qwaq_qwaq_app_obj=$(ruamoko_qwaq_qwaq_app_dat_SOURCES:.r=.o) ruamoko_qwaq_qwaq_app_dep=$(call qcautodep,$(ruamoko_qwaq_qwaq_app_dat_SOURCES:.o=.Qo)) -ruamoko/qwaq/qwaq-app.dat$(EXEEXT): $(ruamoko_qwaq_qwaq_app_obj) $(QFCC_DEP) $(libui) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_qwaq_app_obj) $(libui) -lcsqc -lr +ruamoko/qwaq/qwaq-app.dat$(EXEEXT): $(ruamoko_qwaq_qwaq_app_obj) $(QFCC_DEP) $(libui) ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_qwaq_app_obj) $(libui) -lr include $(ruamoko_qwaq_qwaq_app_dep) # am--include-marker r_depfiles_remade += $(ruamoko_qwaq_qwaq_app_dep) ruamoko_qwaq_input_app_dat_SOURCES=$(qwaq_input_app_dat_src) ruamoko_qwaq_input_app_obj=$(ruamoko_qwaq_input_app_dat_SOURCES:.r=.o) ruamoko_qwaq_input_app_dep=$(call qcautodep,$(ruamoko_qwaq_input_app_dat_SOURCES:.o=.Qo)) -ruamoko/qwaq/input-app.dat$(EXEEXT): $(ruamoko_qwaq_input_app_obj) $(QFCC_DEP) $(libui) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_input_app_obj) $(libui) -lcsqc -lr +ruamoko/qwaq/input-app.dat$(EXEEXT): $(ruamoko_qwaq_input_app_obj) $(QFCC_DEP) $(libui) ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_input_app_obj) $(libui) -lr include $(ruamoko_qwaq_input_app_dep) # am--include-marker r_depfiles_remade += $(ruamoko_qwaq_input_app_dep) ruamoko_qwaq_gcd_dat_SOURCES=ruamoko/qwaq/gcd.r ruamoko_qwaq_gcd_obj=$(ruamoko_qwaq_gcd_dat_SOURCES:.r=.o) ruamoko_qwaq_gcd_dep=$(call qcautodep,$(ruamoko_qwaq_gcd_dat_SOURCES:.o=.Qo)) -ruamoko/qwaq/gcd.dat$(EXEEXT): $(ruamoko_qwaq_gcd_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_gcd_obj) -lcsqc -lr +ruamoko/qwaq/gcd.dat$(EXEEXT): $(ruamoko_qwaq_gcd_obj) $(QFCC_DEP) ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_gcd_obj) -lr include $(ruamoko_qwaq_gcd_dep) # am--include-marker r_depfiles_remade += $(ruamoko_qwaq_gcd_dep) ruamoko_qwaq_z_transform_dat_SOURCES=ruamoko/qwaq/z-transform.r ruamoko_qwaq_z_transform_obj=$(ruamoko_qwaq_z_transform_dat_SOURCES:.r=.o) ruamoko_qwaq_z_transform_dep=$(call qcautodep,$(ruamoko_qwaq_z_transform_dat_SOURCES:.o=.Qo)) -ruamoko/qwaq/z-transform.dat$(EXEEXT): $(ruamoko_qwaq_z_transform_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_z_transform_obj) -lcsqc -lr +ruamoko/qwaq/z-transform.dat$(EXEEXT): $(ruamoko_qwaq_z_transform_obj) $(QFCC_DEP) ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_z_transform_obj) -lr include $(ruamoko_qwaq_z_transform_dep) # am--include-marker r_depfiles_remade += $(ruamoko_qwaq_z_transform_dep) From 1891c1c3025d1315cd0ad81251da31da9f35207d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 21:01:39 +0900 Subject: [PATCH 54/77] [qflight] Replace a sprintf with va While 16 chars is plenty for a 32-bit int, just seeing sprintf is enough reason to make the change. --- tools/qflight/source/entities.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/qflight/source/entities.c b/tools/qflight/source/entities.c index 85ce43431..0157014f8 100644 --- a/tools/qflight/source/entities.c +++ b/tools/qflight/source/entities.c @@ -125,7 +125,7 @@ MatchTargets (void) // set the style on the source ent for switchable lights if (entities[j].style) { entities[i].style = entities[j].style; - SetKeyValue (&entities[i], "style", va (0, "%i", + SetKeyValue (&entities[i], "style", va (0, "%d", entities[i].style)); } @@ -334,12 +334,9 @@ LoadEntities (void) if (entity->classname && !strcmp (entity->classname, "light")) { if (entity->targetname && entity->targetname[0] && !entity->style) { - char s[16]; - entity->style = LightStyleForTargetname (entity->targetname, true); - sprintf (s, "%i", entity->style); - SetKeyValue (entity, "style", s); + SetKeyValue (entity, "style", va (0, "%d", entity->style)); } } } From 675c82b47b23796080fb3890c6ff3951011e5808 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 21:03:34 +0900 Subject: [PATCH 55/77] [nq,qw] Do a little more diff reduction on sbar.c It's rather difficult due to hipnotic and roque in nq, but still, progress is progress. --- nq/source/sbar.c | 234 +++++++++++++++++++++++++++++++++++--- qw/source/sbar.c | 286 +++++++++++++++++++++++++---------------------- 2 files changed, 369 insertions(+), 151 deletions(-) diff --git a/nq/source/sbar.c b/nq/source/sbar.c index df3762ed6..8e298f6aa 100644 --- a/nq/source/sbar.c +++ b/nq/source/sbar.c @@ -216,13 +216,13 @@ draw_altstring (view_t *view, int x, int y, const char *str) { r_funcs->Draw_AltString (view->xabs + x, view->yabs + y, str); } - +#endif static inline void draw_nstring (view_t *view, int x, int y, const char *str, int n) { r_funcs->Draw_nString (view->xabs + x, view->yabs + y, str, n); } -#endif + static inline void draw_fill (view_t *view, int x, int y, int w, int h, int col) { @@ -407,18 +407,25 @@ draw_sigils (view_t *view) static void draw_inventory_sbar (view_t *view) { - printf ("sbar: %d\n", sbar_view->visible); draw_pic (view, 0, 0, sb_ibar); view_draw (view); } +typedef struct { + char team[16 + 1]; + int frags; + int players; + int plow, phigh, ptotal; +} team_t; +team_t teams[MAX_CLIENTS]; +int teamsort[MAX_CLIENTS]; int fragsort[MAX_SCOREBOARD]; char scoreboardtext[MAX_SCOREBOARD][20]; int scoreboardtop[MAX_SCOREBOARD]; int scoreboardbottom[MAX_SCOREBOARD]; int scoreboardcount[MAX_SCOREBOARD]; -int scoreboardlines; +int scoreboardlines, scoreboardteams; static void @@ -436,7 +443,7 @@ Sbar_SortFrags (void) } for (i = 0; i < scoreboardlines; i++) { - for (j = 0; j < (scoreboardlines - 1 - i); j++) { + for (j = 0; j < scoreboardlines - 1 - i; j++) { if (cl.players[fragsort[j]].frags < cl.players[fragsort[j + 1]].frags) { k = fragsort[j]; @@ -447,12 +454,77 @@ Sbar_SortFrags (void) } } +static void +Sbar_SortTeams (void) +{ + char t[16 + 1]; + int i, j, k; + player_info_t *s; + + // request new ping times every two second + scoreboardteams = 0; + + if (!cl.teamplay) + return; + + // sort the teams + memset (teams, 0, sizeof (teams)); + for (i = 0; i < MAX_CLIENTS; i++) + teams[i].plow = 999; + + for (i = 0; i < MAX_CLIENTS; i++) { + s = &cl.players[i]; + if (!s->name || !s->name->value[0]) + continue; + if (s->spectator) + continue; + + // find his team in the list + t[16] = 0; + strncpy (t, s->team->value, 16); + if (!t[0]) + continue; // not on team + for (j = 0; j < scoreboardteams; j++) + if (!strcmp (teams[j].team, t)) { + teams[j].frags += s->frags; + teams[j].players++; + goto addpinginfo; + } + if (j == scoreboardteams) { // must add him + j = scoreboardteams++; + strcpy (teams[j].team, t); + teams[j].frags = s->frags; + teams[j].players = 1; + addpinginfo: + if (teams[j].plow > s->ping) + teams[j].plow = s->ping; + if (teams[j].phigh < s->ping) + teams[j].phigh = s->ping; + teams[j].ptotal += s->ping; + } + } + + // sort + for (i = 0; i < scoreboardteams; i++) + teamsort[i] = i; + + // good 'ol bubble sort + for (i = 0; i < scoreboardteams - 1; i++) { + for (j = i + 1; j < scoreboardteams; j++) { + if (teams[teamsort[i]].frags < teams[teamsort[j]].frags) { + k = teamsort[i]; + teamsort[i] = teamsort[j]; + teamsort[j] = k; + } + } + } +} static void draw_solo (view_t *view) { char str[80]; - int minutes, seconds, tens, units; + int minutes, seconds; int l; draw_pic (view, 0, 0, sb_scorebar); @@ -467,10 +539,8 @@ draw_solo (view_t *view) // time minutes = cl.time / 60; - seconds = cl.time - (60 * minutes); - tens = seconds / 10; - units = seconds - (10 * tens); - snprintf (str, sizeof (str), "Time :%3i:%i%i", minutes, tens, units); + seconds = cl.time - 60 * minutes; + snprintf (str, sizeof (str), "Time :%3i:%02i", minutes, seconds); draw_string (view, 184, 4, str); // draw level name @@ -500,7 +570,7 @@ draw_frags (view_t *view) for (i = 0; i < l; i++) { k = fragsort[i]; s = &cl.players[k]; - if (!s->name->value[0]) + if (!s->name || !s->name->value[0]) continue; // draw background @@ -1191,6 +1261,120 @@ Sbar_DrawCenterPrint (void) Sbar_DrawCenterString (hud_overlay_view, -1); } +/* + draw_minifrags + + frags name + frags team name + displayed to right of status bar if there's room +*/ +static void +draw_minifrags (view_t *view) +{ + int numlines, top, bottom, f, i, k, x, y; + char num[20]; + player_info_t *s; + + r_data->scr_copyeverything = 1; + r_data->scr_fullupdate = 0; + + // scores + Sbar_SortFrags (); + + if (!scoreboardlines) + return; // no one there? + + numlines = view->ylen / 8; + if (numlines < 3) + return; // not enough room + + // find us + for (i = 0; i < scoreboardlines; i++) + if (fragsort[i] == cl.playernum) + break; + + if (i == scoreboardlines) // we're not there, we are probably a + // spectator, just display top + i = 0; + else // figure out start + i = i - numlines / 2; + + if (i > scoreboardlines - numlines) + i = scoreboardlines - numlines; + if (i < 0) + i = 0; + + x = 4; + y = 0; + + for (; i < scoreboardlines && y < view->ylen - 8 + 1; i++) { + k = fragsort[i]; + s = &cl.players[k]; + if (!s->name || !s->name->value[0]) + continue; + + // draw ping + top = s->topcolor; + bottom = s->bottomcolor; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + draw_fill (view, x + 2, y + 1, 37, 3, top); + draw_fill (view, x + 2, y + 4, 37, 4, bottom); + + // draw number + f = s->frags; + if (k != cl.playernum) { + snprintf (num, sizeof (num), " %3i ", f); + } else { + snprintf (num, sizeof (num), "\x10%3i\x11", f); + } + + draw_nstring (view, x, y, num, 5); + + // team + if (cl.teamplay) { + draw_nstring (view, x + 48, y, s->team->value, 4); + draw_nstring (view, x + 48 + 40, y, s->name->value, 16); + } else + draw_nstring (view, x + 48, y, s->name->value, 16); + y += 8; + } +} + +static void +draw_miniteam (view_t *view) +{ + int i, k, x, y; + char num[12]; + info_key_t *player_team = cl.players[cl.playernum].team; + team_t *tm; + + if (!cl.teamplay) + return; + Sbar_SortTeams (); + + x = 0; + y = 0; + for (i = 0; i < scoreboardteams && y <= view->ylen; i++) { + k = teamsort[i]; + tm = teams + k; + + // draw pings + draw_nstring (view, x, y, tm->team, 4); + // draw total + snprintf (num, sizeof (num), "%5i", tm->frags); + draw_string (view, x + 40, y, num); + + if (player_team && strnequal (player_team->value, tm->team, 16)) { + draw_character (view, x - 8, y, 16); + draw_character (view, x + 32, y, 17); + } + + y += 8; + } +} + static void init_sbar_views (void) { @@ -1252,16 +1436,36 @@ static void init_hud_views (void) { view_t *view; + view_t *minifrags_view = 0; + view_t *miniteam_view = 0; - hud_view = view_new (0, 0, 320, 48, grav_south); - hud_frags_view = view_new (0, 0, 130, 8, grav_northeast); - hud_frags_view->draw = draw_frags; + if (r_data->vid->conview->xlen < 512) { + hud_view = view_new (0, 0, 320, 48, grav_south); + hud_frags_view = view_new (0, 0, 130, 8, grav_northeast); + hud_frags_view->draw = draw_frags; + } else if (r_data->vid->conview->xlen < 640) { + hud_view = view_new (0, 0, 512, 48, grav_south); + + minifrags_view = view_new (320, 0, 192, 48, grav_southwest); + minifrags_view->draw = draw_minifrags; + minifrags_view->resize_y = 1; + } else { + hud_view = view_new (0, 0, 640, 48, grav_south); + + minifrags_view = view_new (320, 0, 192, 48, grav_southwest); + minifrags_view->draw = draw_minifrags; + minifrags_view->resize_y = 1; + + miniteam_view = view_new (0, 0, 96, 48, grav_southeast); + miniteam_view->draw = draw_miniteam; + miniteam_view->resize_y = 1; + } hud_view->resize_y = 1; hud_armament_view = view_new (0, 48, 42, 156, grav_southeast); - view = view_new (0, 0, 24, 112, grav_northeast); + view = view_new (0, 0, 42, 112, grav_northeast); view->draw = draw_weapons_hud; view_add (hud_armament_view, view); diff --git a/qw/source/sbar.c b/qw/source/sbar.c index bd717a1c2..ebc9d267e 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -292,123 +292,6 @@ draw_num (view_t *view, int x, int y, int num, int digits, int color) } } -typedef struct { - char team[16 + 1]; - int frags; - int players; - int plow, phigh, ptotal; -} team_t; - -team_t teams[MAX_CLIENTS]; -int teamsort[MAX_CLIENTS]; -int fragsort[MAX_CLIENTS]; // ZOID changed this from [MAX_SCOREBOARD] -int scoreboardlines, scoreboardteams; - -static void -Sbar_SortFrags (qboolean includespec) -{ - int i, j, k; - - // sort by frags - scoreboardlines = 0; - for (i = 0; i < MAX_CLIENTS; i++) { - if (cl.players[i].name && cl.players[i].name->value[0] - && (!cl.players[i].spectator || includespec)) { - fragsort[scoreboardlines] = i; - scoreboardlines++; - if (cl.players[i].spectator) - cl.players[i].frags = -999; - } - } - - for (i = 0; i < scoreboardlines; i++) - for (j = 0; j < scoreboardlines - 1 - i; j++) - if (cl.players[fragsort[j]].frags < - cl.players[fragsort[j + 1]].frags) { - k = fragsort[j]; - fragsort[j] = fragsort[j + 1]; - fragsort[j + 1] = k; - } -} - -static void -Sbar_SortTeams (void) -{ - char t[16 + 1]; - int i, j, k; - player_info_t *s; - - // request new ping times every two second - scoreboardteams = 0; - - if (!cl.teamplay) - return; - - // sort the teams - memset (teams, 0, sizeof (teams)); - for (i = 0; i < MAX_CLIENTS; i++) - teams[i].plow = 999; - - for (i = 0; i < MAX_CLIENTS; i++) { - s = &cl.players[i]; - if (!s->name || !s->name->value[0]) - continue; - if (s->spectator) - continue; - - // find his team in the list - t[16] = 0; - strncpy (t, s->team->value, 16); - if (!t[0]) - continue; // not on team - for (j = 0; j < scoreboardteams; j++) - if (!strcmp (teams[j].team, t)) { - teams[j].frags += s->frags; - teams[j].players++; - goto addpinginfo; - } - if (j == scoreboardteams) { // must add him - j = scoreboardteams++; - strcpy (teams[j].team, t); - teams[j].frags = s->frags; - teams[j].players = 1; - addpinginfo: - if (teams[j].plow > s->ping) - teams[j].plow = s->ping; - if (teams[j].phigh < s->ping) - teams[j].phigh = s->ping; - teams[j].ptotal += s->ping; - } - } - - // sort - for (i = 0; i < scoreboardteams; i++) - teamsort[i] = i; - - // good 'ol bubble sort - for (i = 0; i < scoreboardteams - 1; i++) - for (j = i + 1; j < scoreboardteams; j++) - if (teams[teamsort[i]].frags < teams[teamsort[j]].frags) { - k = teamsort[i]; - teamsort[i] = teamsort[j]; - teamsort[j] = k; - } -} - -static void -draw_solo (view_t *view) -{ - char str[80]; - int minutes, seconds; - - draw_pic (view, 0, 0, sb_scorebar); - - minutes = cl.time / 60; - seconds = cl.time - 60 * minutes; - snprintf (str, sizeof (str), "Time :%3i:%02i", minutes, seconds); - draw_string (view, 184, 4, str); -} - static inline void draw_smallnum (view_t *view, int x, int y, int n, int packed, int colored) { @@ -567,6 +450,127 @@ draw_inventory_sbar (view_t *view) view_draw (view); } +typedef struct { + char team[16 + 1]; + int frags; + int players; + int plow, phigh, ptotal; +} team_t; + +team_t teams[MAX_CLIENTS]; +int teamsort[MAX_CLIENTS]; +int fragsort[MAX_CLIENTS]; // ZOID changed this from [MAX_SCOREBOARD] +int scoreboardlines, scoreboardteams; + +static void +Sbar_SortFrags (qboolean includespec) +{ + int i, j, k; + + // sort by frags + scoreboardlines = 0; + for (i = 0; i < MAX_CLIENTS; i++) { + if (cl.players[i].name && cl.players[i].name->value[0] + && (!cl.players[i].spectator || includespec)) { + fragsort[scoreboardlines] = i; + scoreboardlines++; + if (cl.players[i].spectator) + cl.players[i].frags = -999; + } + } + + for (i = 0; i < scoreboardlines; i++) { + for (j = 0; j < scoreboardlines - 1 - i; j++) { + if (cl.players[fragsort[j]].frags < + cl.players[fragsort[j + 1]].frags) { + k = fragsort[j]; + fragsort[j] = fragsort[j + 1]; + fragsort[j + 1] = k; + } + } + } +} + +static void +Sbar_SortTeams (void) +{ + char t[16 + 1]; + int i, j, k; + player_info_t *s; + + // request new ping times every two second + scoreboardteams = 0; + + if (!cl.teamplay) + return; + + // sort the teams + memset (teams, 0, sizeof (teams)); + for (i = 0; i < MAX_CLIENTS; i++) + teams[i].plow = 999; + + for (i = 0; i < MAX_CLIENTS; i++) { + s = &cl.players[i]; + if (!s->name || !s->name->value[0]) + continue; + if (s->spectator) + continue; + + // find his team in the list + t[16] = 0; + strncpy (t, s->team->value, 16); + if (!t[0]) + continue; // not on team + for (j = 0; j < scoreboardteams; j++) + if (!strcmp (teams[j].team, t)) { + teams[j].frags += s->frags; + teams[j].players++; + goto addpinginfo; + } + if (j == scoreboardteams) { // must add him + j = scoreboardteams++; + strcpy (teams[j].team, t); + teams[j].frags = s->frags; + teams[j].players = 1; + addpinginfo: + if (teams[j].plow > s->ping) + teams[j].plow = s->ping; + if (teams[j].phigh < s->ping) + teams[j].phigh = s->ping; + teams[j].ptotal += s->ping; + } + } + + // sort + for (i = 0; i < scoreboardteams; i++) + teamsort[i] = i; + + // good 'ol bubble sort + for (i = 0; i < scoreboardteams - 1; i++) { + for (j = i + 1; j < scoreboardteams; j++) { + if (teams[teamsort[i]].frags < teams[teamsort[j]].frags) { + k = teamsort[i]; + teamsort[i] = teamsort[j]; + teamsort[j] = k; + } + } + } +} + +static void +draw_solo (view_t *view) +{ + char str[80]; + int minutes, seconds; + + draw_pic (view, 0, 0, sb_scorebar); + + minutes = cl.time / 60; + seconds = cl.time - 60 * minutes; + snprintf (str, sizeof (str), "Time :%3i:%02i", minutes, seconds); + draw_string (view, 184, 4, str); +} + static inline void dmo_ping (view_t *view, int x, int y, player_info_t *s) { @@ -697,9 +701,6 @@ draw_frags (view_t *view) continue; // draw background - top = bound (0, s->topcolor, 13); - bottom = bound (0, s->bottomcolor, 13); - top = Sbar_ColorForMap (top); bottom = Sbar_ColorForMap (bottom); @@ -785,18 +786,9 @@ draw_status_bar (view_t *view) draw_pic (view, 0, 0, sb_sbar); } -static void -draw_status (view_t *view) +static inline void +draw_armor (view_t *view) { - if (cl.spectator) { - draw_spectator (view); - if (autocam != CAM_TRACK) - return; - } if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) { - draw_solo (view); - return; - } - // armor if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) { draw_num (view, 24, 0, 666, 3, 1); } else { @@ -809,15 +801,18 @@ draw_status (view_t *view) else if (cl.stats[STAT_ITEMS] & IT_ARMOR1) draw_pic (view, 0, 0, sb_armor[0]); } +} - // face - draw_face (view); - - // health +static inline void +draw_health (view_t *view) +{ draw_num (view, 136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25); +} - // ammo icon +static inline void +draw_ammo (view_t *view) +{ if (cl.stats[STAT_ITEMS] & IT_SHELLS) draw_pic (view, 224, 0, sb_ammo[0]); else if (cl.stats[STAT_ITEMS] & IT_NAILS) @@ -830,6 +825,25 @@ draw_status (view_t *view) draw_num (view, 248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10); } +static void +draw_status (view_t *view) +{ + if (cl.spectator) { + draw_spectator (view); + if (autocam != CAM_TRACK) + return; + } + if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) { + draw_solo (view); + return; + } + + draw_armor (view); + draw_face (view); + draw_health (view); + draw_ammo (view); +} + /* Sbar_DeathmatchOverlay From bbb66e13f82db4d21adc30ad610e42f530b89cf2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 22:37:52 +0900 Subject: [PATCH 56/77] [nq] Fix incorrect handling of argv in PF_WriteBytes This fixes an illegible server message error on going through a teleport in the start map (how I noticed the problem). Funnily enough, I had spotted the mistake when editing the qw version, but forgot to correct the nq version. --- nq/source/sv_pr_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index b133b0bf4..b555708ff 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -1139,7 +1139,7 @@ PF_WriteBytes (progs_t *pr, void *data) } } for (i = 0; i < argc; i++) { - p = PR_PTR (float, &argv[i]); + p = PR_PTR (float, argv[i]); MSG_WriteByte (msg, p); } } From 618453629fc56fd4600b86c5bae9879e6c208743 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 23:13:24 +0900 Subject: [PATCH 57/77] [qw] Call SV_Physics_Init_Cvars during server init This fixes the broken physics. Really, not that bad considering how extensive the cvar revamp was. --- qw/source/sv_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index fbb111ab1..e2d64d170 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -2355,6 +2355,7 @@ SV_InitLocal (void) int i; SV_UserInit (); + SV_Physics_Init_Cvars (); Cvar_Register (&rcon_password_cvar, 0, 0); Cvar_Register (&admin_password_cvar, 0, 0); From e1f4df27c31091856032dfcea64494025feddd87 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 May 2022 23:52:26 +0900 Subject: [PATCH 58/77] [qw] Fix inverted chat mode This has been bugging me for a while whenever I tested qw. Just a silly logic error. The whole system needs work, though. --- qw/source/cl_chat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qw/source/cl_chat.c b/qw/source/cl_chat.c index 5e170c3c9..81e9c8b4b 100644 --- a/qw/source/cl_chat.c +++ b/qw/source/cl_chat.c @@ -255,7 +255,7 @@ static void cl_chat_on_focus_change (int game) { //FIXME afk mode - CL_ChatInfo (!!game); + CL_ChatInfo (!game); } From e323fbbbed7a5441b488f8157f51610cf9362501 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 08:40:02 +0900 Subject: [PATCH 59/77] [vulkan] Rework lighting model to be more algebraic This leaves only the one conditional in the shader code, that being the distance check. It doesn't seem to make any noticeable difference to performance, but other than explosion sprites being blue, lighting quality seems to have improved. However, I really need to get shadows working: marcher is just silly-bright without them, and light levels changing as I move around is a bit disconcerting (but reasonable as those lights' leaf nodes go in and out of visibility). --- include/QF/Vulkan/qf_lighting.h | 44 ++-- .../renderer/vulkan/shader/lighting.frag | 127 +++------- libs/video/renderer/vulkan/vulkan_lighting.c | 221 ++++++++++++------ 3 files changed, 192 insertions(+), 200 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index ec4de2c3f..f8b6e5d84 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -39,12 +39,10 @@ #include "QF/simd/types.h" typedef struct qfv_light_s { - vec3_t color; - int data; - vec3_t position; - float light; - vec3_t direction; - float cone; + vec4f_t color; + vec4f_t position; + vec4f_t direction; + vec4f_t attenuation; } qfv_light_t; typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t; @@ -54,32 +52,25 @@ typedef struct qfv_lightmatset_s DARRAY_TYPE (mat4f_t) qfv_lightmatset_t; #define MaxLights 256 -#define StyleMask 0x07f -#define ModelMask 0x380 -#define ShadowMask 0xc00 +#define LM_LINEAR 0 // light - dist (or radius + dist if -ve) +#define LM_INVERSE 1 // distFactor1 * light / dist +#define LM_INVERSE2 2 // distFactor2 * light / (dist * dist) +#define LM_INFINITE 3 // light +#define LM_AMBIENT 4 // light +#define LM_INVERSE3 5 // distFactor2 * light / (dist + distFactor2)**2 -#define LM_LINEAR (0 << 7) // light - dist (or radius + dist if -ve) -#define LM_INVERSE (1 << 7) // distFactor1 * light / dist -#define LM_INVERSE2 (2 << 7) // distFactor2 * light / (dist * dist) -#define LM_INFINITE (3 << 7) // light -#define LM_AMBIENT (4 << 7) // light -#define LM_INVERSE3 (5 << 7) // distFactor2 * light / (dist + distFactor2)**2 - -#define ST_NONE (0 << 10) // no shadows -#define ST_PLANE (1 << 10) // single plane shadow map (small spotlight) -#define ST_CASCADE (2 << 10) // cascaded shadow maps -#define ST_CUBE (3 << 10) // cubemap (omni, large spotlight) +#define ST_NONE 0 // no shadows +#define ST_PLANE 1 // single plane shadow map (small spotlight) +#define ST_CASCADE 2 // cascaded shadow maps +#define ST_CUBE 3 // cubemap (omni, large spotlight) #define NumStyles 64 typedef struct qfv_light_buffer_s { - float intensity[NumStyles + 4]; - float distFactor1; - float distFactor2; - int lightCount; qfv_light_t lights[MaxLights] __attribute__((aligned(16))); - mat4f_t shadowMat[MaxLights]; - vec4f_t shadowCascade[MaxLights]; + int lightCount; + //mat4f_t shadowMat[MaxLights]; + //vec4f_t shadowCascade[MaxLights]; } qfv_light_buffer_t; #define LIGHTING_BUFFER_INFOS 1 @@ -119,6 +110,7 @@ typedef struct lightingctx_s { VkDeviceMemory light_memory; VkDeviceMemory shadow_memory; qfv_lightset_t lights; + qfv_lightintset_t lightstyles; qfv_lightintset_t lightleafs; qfv_lightmatset_t lightmats; qfv_imageset_t lightimages; diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 2d384e622..a9e5cb7d2 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -7,12 +7,10 @@ layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput n layout (input_attachment_index = 4, set = 0, binding = 4) uniform subpassInput position; struct LightData { - vec3 color; - int data;// bits 0-6: intensity key (however, values 0-66) - vec3 position; - float light; // doubles as radius for linear - vec3 direction; - float cone; + vec4 color; // .a is intensity + vec4 position; // .w = 0 -> directional, .w = 1 -> point/cone + vec4 direction; // .w = -cos(cone_angle/2) (1 for omni/dir) + vec4 attenuation; }; #define StyleMask 0x07f @@ -38,13 +36,10 @@ layout (set = 2, binding = 0) uniform sampler2DShadow shadowPlane[MaxLights]; layout (set = 2, binding = 0) uniform samplerCubeShadow shadowCube[MaxLights]; layout (set = 1, binding = 0) uniform Lights { - vec4 intensity[17]; // 68 floats - float distFactor1; // for inverse - float distFactor2; // for inverse2 and inverse3 - int lightCount; LightData lights[MaxLights]; - mat4 shadowMat[MaxLights]; - vec4 shadowCascale[MaxLights]; + int lightCount; + //mat4 shadowMat[MaxLights]; + //vec4 shadowCascale[MaxLights]; }; layout (location = 0) out vec4 frag_color; @@ -52,8 +47,10 @@ layout (location = 0) out vec4 frag_color; float spot_cone (LightData light, vec3 incoming) { - float spotdot = dot (incoming, light.direction); - return smoothstep (spotdot, 1 - (1 - spotdot) * 0.995, light.cone); + vec3 dir = light.direction.xyz; + float cone = light.direction.w; + float spotdot = dot (incoming, dir); + return 1 - smoothstep (cone, cone + 0.02, spotdot); } float @@ -63,50 +60,6 @@ diffuse (vec3 incoming, vec3 normal) return clamp (lightdot, 0, 1); } -float -light_linear (LightData light, float d) -{ - float l = light.light; - if (l < 0) { - return min (l + d, 0); - } else { - return max (l - d, 0); - } -} - -float -light_inverse (LightData light, float d) -{ - float l = light.light; - return l / (distFactor1 * d); -} - -float -light_inverse2 (LightData light, float d) -{ - float l = light.light; - return l / (distFactor2 * d); -} - -float -light_infinite (LightData light) -{ - return light.light; -} - -float -light_ambient (LightData light) -{ - return light.light; -} - -float -light_inverse3 (LightData light, float d) -{ - float l = light.light; - return l / (distFactor2 * d + 1); -} - float shadow_cascade (sampler2DArrayShadow map) { @@ -138,55 +91,31 @@ main (void) if (MaxLights > 0) { vec3 minLight = vec3 (0); for (int i = 0; i < lightCount; i++) { - vec3 dist = lights[i].position - p; - float d = dot (dist, dist); - int model = lights[i].data & ModelMask; + LightData l = lights[i]; + vec3 dir = l.position.xyz - l.position.w * p; + float r2 = dot (dir, dir); + vec4 a = l.attenuation; - if (model != LM_INFINITE - && d > lights[i].light * lights[i].light) { + if (l.position.w * a.w * a.w * r2 >= 1) { continue; } + vec4 r = vec4 (r2, sqrt(r2), 1, 0); + vec3 incoming = dir / r.y; + float I = (1 - a.w * r.y) / dot (a, r); - float l = 0; - if (model == LM_LINEAR) { - d = sqrt (d); - l = light_linear (lights[i], d); - } else if (model == LM_INVERSE) { - d = sqrt (d); - l = light_inverse (lights[i], d); - } else if (model == LM_INVERSE2) { - l = light_inverse2 (lights[i], d); - d = sqrt (d); - } else if (model == LM_INFINITE) { - l = light_infinite (lights[i]); - dist = lights[i].direction; - d = -1; - } else if (model == LM_AMBIENT) { - l = light_ambient (lights[i]); - } else if (model == LM_INVERSE3) { - l = light_inverse3 (lights[i], d); - d = sqrt (d); - } - - int style = lights[i].data & StyleMask; - l *= intensity[style / 4][style % 4]; - - int shadow = lights[i].data & ShadowMask; + /*int shadow = lights[i].data & ShadowMask; if (shadow == ST_CASCADE) { - l *= shadow_cascade (shadowCascade[i]); + I *= shadow_cascade (shadowCascade[i]); } else if (shadow == ST_PLANE) { - l *= shadow_plane (shadowPlane[i]); + I *= shadow_plane (shadowPlane[i]); } else if (shadow == ST_CUBE) { - l *= shadow_cube (shadowCube[i]); - } + I *= shadow_cube (shadowCube[i]); + }*/ - if (model == LM_AMBIENT) { - minLight = max (l * lights[i].color, minLight); - } else { - vec3 incoming = dist / d; - l *= spot_cone (lights[i], incoming) * diffuse (incoming, n); - light += l * lights[i].color; - } + float namb = dot(l.direction.xyz, l.direction.xyz); + I *= spot_cone (l, incoming) * diffuse (incoming, n); + I = mix (1, I, namb); + light += I * l.color.w * l.color.xyz; } light = max (light, minLight); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 33b13a22d..7a97377d3 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -147,17 +147,10 @@ update_lights (vulkan_ctx_t *ctx) qfv_light_buffer_t *light_data = QFV_PacketExtend (packet, sizeof (*light_data)); + float style_intensities[NumStyles]; for (int i = 0; i < NumStyles; i++) { - light_data->intensity[i] = d_lightstylevalue[i] / 65536.0; + style_intensities[i] = d_lightstylevalue[i] / 65536.0; } - // dynamic lights seem a tad faint, so 16x map lights - light_data->intensity[64] = 1 / 16.0; - light_data->intensity[65] = 1 / 16.0; - light_data->intensity[66] = 1 / 16.0; - light_data->intensity[67] = 1 / 16.0; - - light_data->distFactor1 = 1 / 128.0; - light_data->distFactor2 = 1 / 16384.0; light_data->lightCount = 0; R_FindNearLights (r_refdef.frame.position, MaxLights - 1, lights); @@ -167,16 +160,20 @@ update_lights (vulkan_ctx_t *ctx) } light_data->lightCount++; VectorCopy (lights[i]->color, light_data->lights[i].color); + // dynamic lights seem a tad faint, so 16x map lights + light_data->lights[i].color[3] = lights[i]->radius / 16; VectorCopy (lights[i]->origin, light_data->lights[i].position); - light_data->lights[i].light = lights[i]->radius; - light_data->lights[i].data = 64; // default dynamic light - VectorZero (light_data->lights[i].direction); - light_data->lights[i].cone = 1; + light_data->lights[i].attenuation = + (vec4f_t) { 0, 0, 1, 1/lights[i]->radius }; + light_data->lights[i].direction = + (vec4f_t) { 0, 0, 1, 1 }; } for (size_t i = 0; (i < lframe->lightvis.size && light_data->lightCount < MaxLights); i++) { if (lframe->lightvis.a[i]) { - light_data->lights[light_data->lightCount++] = lctx->lights.a[i]; + qfv_light_t *light = &light_data->lights[light_data->lightCount++]; + *light = lctx->lights.a[i]; + light->color[3] *= style_intensities[lctx->lightstyles.a[i]]; } } @@ -303,6 +300,7 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) ctx->lighting_context = lctx; DARRAY_INIT (&lctx->lights, 16); + DARRAY_INIT (&lctx->lightstyles, 16); DARRAY_INIT (&lctx->lightleafs, 16); DARRAY_INIT (&lctx->lightmats, 16); DARRAY_INIT (&lctx->lightlayers, 16); @@ -462,6 +460,7 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0); dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); DARRAY_CLEAR (&lctx->lights); + DARRAY_CLEAR (&lctx->lightstyles); DARRAY_CLEAR (&lctx->lightleafs); DARRAY_CLEAR (&lctx->lightmats); DARRAY_CLEAR (&lctx->lightimages); @@ -475,19 +474,17 @@ static void dump_light (qfv_light_t *light, int leaf, mat4f_t mat) { Sys_MaskPrintf (SYS_vulkan, - "[%g, %g, %g] %d %d %d, " - "[%g %g %g] %g, [%g %g %g] %g, %d\n", - VectorExpand (light->color), - (light->data & 0x07f), - (light->data & 0x380) >> 7, - (light->data & 0xc00) >> 10, - VectorExpand (light->position), light->light, - VectorExpand (light->direction), light->cone, + "[%g, %g, %g] %g, " + "[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n", + VEC4_EXP (light->color), + VEC4_EXP (light->position), + VEC4_EXP (light->direction), + VEC4_EXP (light->attenuation), leaf); - Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 0)); - Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 1)); - Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 2)); - Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 3)); +// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 0)); +// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 1)); +// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 2)); +// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 3)); } static float @@ -548,13 +545,17 @@ esin (float ang) return sin (ang * M_PI / 180); } -static void -sun_vector (const vec_t *ang, vec_t *vec) +static vec4f_t +sun_vector (const vec_t *ang) { // ang is yaw, pitch (maybe roll, but ignored - vec[0] = ecos (ang[1]) * ecos (ang[0]); - vec[1] = ecos (ang[1]) * esin (ang[0]); - vec[2] = esin (ang[1]); + vec4f_t vec = { + ecos (ang[1]) * ecos (ang[0]), + ecos (ang[1]) * esin (ang[0]), + esin (ang[1]), + 0, + }; + return vec; } static void @@ -577,11 +578,13 @@ parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model) return; } VectorSet (1, 1, 1, light.color); - light.data = LM_INFINITE | ST_CASCADE; - light.light = sunlight; - sun_vector (sunangle, light.direction); - light.cone = 1; + light.color[3] = sunlight; + light.position = sun_vector (sunangle); + light.direction = light.position; + light.direction[3] = 1; + light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; DARRAY_APPEND (&lctx->lights, light); + DARRAY_APPEND (&lctx->lightstyles, 0); DARRAY_APPEND (&lctx->lightleafs, -1); // Any leaf with sky surfaces can potentially see the sun, thus put @@ -597,8 +600,16 @@ parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model) expand_pvs (lctx->sun_pvs, model); } +static vec4f_t +parse_position (const char *str) +{ + vec3_t vec = {}; + sscanf (str, "%f %f %f", VectorExpandAddr (vec)); + return (vec4f_t) {vec[0], vec[1], vec[2], 1}; +} + static void -parse_light (qfv_light_t *light, const plitem_t *entity, +parse_light (qfv_light_t *light, int *style, const plitem_t *entity, const plitem_t *targets) { const char *str; @@ -612,48 +623,47 @@ parse_light (qfv_light_t *light, const plitem_t *entity, } Sys_Printf ("}\n");*/ - light->cone = 1; - light->data = 0; - light->light = 300; - VectorSet (1, 1, 1, light->color); + // omnidirectional light (unit length xyz so not treated as ambient) + light->direction = (vec4f_t) { 0, 0, 1, 1 }; + // bright white + light->color = (vec4f_t) { 1, 1, 1, 300 }; if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { - sscanf (str, "%f %f %f", VectorExpandAddr (light->position)); + light->position = parse_position (str); } if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { - vec3_t position = {}; plitem_t *target = PL_ObjectForKey (targets, str); + vec4f_t dir = { 1, 0, 0, 0 }; if (target) { if ((str = PL_String (PL_ObjectForKey (target, "origin")))) { - sscanf (str, "%f %f %f", VectorExpandAddr (position)); + dir = parse_position (str); + dir = normalf (dir - light->position); } - VectorSubtract (position, light->position, light->direction); - VectorNormalize (light->direction); } float angle = 40; if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) { angle = atof (str); } - light->cone = -cos (angle * M_PI / 360); // half angle + dir[3] = -cos (angle * M_PI / 360); // half angle + light->direction = dir; } if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { - light->light = atof (str); + light->color[3] = atof (str); } if ((str = PL_String (PL_ObjectForKey (entity, "style")))) { - light->data = atoi (str) & 0x3f; + *style = atoi (str) & 0x3f; } if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) { - model = (atoi (str) & 0x7) << 7; + model = atoi (str) & 0x7; if (model == LM_INVERSE2) { model = LM_INVERSE3; //FIXME for marcher (need a map) } - light->data |= model; } if ((str = PL_String (PL_ObjectForKey (entity, "color"))) @@ -662,15 +672,29 @@ parse_light (qfv_light_t *light, const plitem_t *entity, VectorScale (light->color, 1/255.0, light->color); } - if (model == LM_INFINITE) { - light->data |= ST_CASCADE; - } else if (model != LM_AMBIENT) { - if (light->cone > -0.5) { - light->data |= ST_CUBE; - } else { - light->data |= ST_PLANE; - } + vec4f_t attenuation = { 1, 0, 0, 0 }; // inverse square + switch (model) { + case LM_LINEAR: + attenuation = (vec4f_t) { 0, 0, 1, 1 / fabsf (light->color[3]) }; + break; + case LM_INVERSE: + attenuation = (vec4f_t) { 0, 1.0 / 128, 0, 0 }; + break; + case LM_INVERSE2: + attenuation = (vec4f_t) { 1.0 / 16384, 0, 0, 0 }; + break; + case LM_INFINITE: + attenuation = (vec4f_t) { 0, 0, 1, 0 }; + break; + case LM_AMBIENT: + attenuation = (vec4f_t) { 0, 0, 1, 0 }; + light->direction = (vec4f_t) { 0, 0, 0, 1 }; + break; + case LM_INVERSE3: + attenuation = (vec4f_t) { 1.0 / 16384, 2.0 / 128, 1, 0 }; + break; } + light->attenuation = attenuation; } static void @@ -681,8 +705,18 @@ create_light_matrices (lightingctx_t *lctx) qfv_light_t *light = &lctx->lights.a[i]; mat4f_t view; mat4f_t proj; + int mode = ST_NONE; - switch (light->data & ShadowMask) { + if (!light->position[3]) { + mode = ST_CASCADE; + } else { + if (light->direction[3] > -0.5) { + mode = ST_CUBE; + } else { + mode = ST_PLANE; + } + } + switch (mode) { default: case ST_NONE: case ST_CUBE: @@ -691,13 +725,14 @@ create_light_matrices (lightingctx_t *lctx) case ST_CASCADE: case ST_PLANE: //FIXME will fail for -ref_direction - mat4fquat (view, qrotf (loadvec3f (light->direction), - ref_direction)); + vec4f_t dir = light->direction; + dir[3] = 0; + mat4fquat (view, qrotf (dir, ref_direction)); break; } VectorNegate (light->position, view[3]); - switch (light->data & ShadowMask) { + switch (mode) { case ST_NONE: mat4fidentity (proj); break; @@ -709,7 +744,7 @@ create_light_matrices (lightingctx_t *lctx) mat4fidentity (proj); break; case ST_PLANE: - QFV_PerspectiveCos (proj, light->cone); + QFV_PerspectiveCos (proj, -light->direction[3]); break; } mmulf (lctx->lightmats.a[i], proj, view); @@ -722,10 +757,11 @@ light_compare (const void *_l2, const void *_l1) const qfv_light_t *l1 = _l1; const qfv_light_t *l2 = _l2; - if (l1->light == l2->light) { - return (l1->data & ShadowMask) - (l2->data & ShadowMask); + if (l1->color[3] == l2->color[3]) { + return (l1->position[3] == l2->position[3]) + && (l1->direction[3] > -0.5) == (l2->direction[3] > -0.5); } - return l1->light - l2->light; + return l1->color[3] - l2->color[3]; } static VkImage @@ -758,7 +794,7 @@ create_map (int size, int layers, int cube, vulkan_ctx_t *ctx) } static VkImageView -create_view (VkImage image, int baseLayer, int data, int id, vulkan_ctx_t *ctx) +create_view (VkImage image, int baseLayer, int mode, int id, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -767,7 +803,7 @@ create_view (VkImage image, int baseLayer, int data, int id, vulkan_ctx_t *ctx) VkImageViewType type = 0; const char *viewtype = 0; - switch (data & ShadowMask) { + switch (mode) { case ST_NONE: return 0; case ST_PLANE: @@ -827,8 +863,18 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) DARRAY_RESIZE (&lctx->lightlayers, numLights); qsort (lights, numLights, sizeof (qfv_light_t), light_compare); for (int i = 0; i < numLights; i++) { - int shadow = lights[i].data & ShadowMask; int layers = 1; + int shadow = ST_NONE; + + if (!lights[i].position[3]) { + shadow = ST_CASCADE; + } else { + if (lights[i].direction[3] > -0.5) { + shadow = ST_CUBE; + } else { + shadow = ST_PLANE; + } + } if (shadow == ST_CASCADE || shadow == ST_NONE) { // cascade shadows will be handled separately, and "none" has no // shadow map at all @@ -838,13 +884,14 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) if (shadow == ST_CUBE) { layers = 6; } - if (size != (int) lights[i].light || numLayers + layers > maxLayers) { + if (size != (int) lights[i].color[3] + || numLayers + layers > maxLayers) { if (numLayers) { VkImage shadow_map = create_map (size, numLayers, 1, ctx); DARRAY_APPEND (&lctx->lightimages, shadow_map); numLayers = 0; } - size = lights[i].light; + size = lights[i].color[3]; } imageMap[i] = lctx->lightimages.size; lctx->lightlayers.a[i] = numLayers; @@ -859,8 +906,18 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) numLayers = 0; size = 1024; for (int i = 0; i < numLights; i++) { - int shadow = lights[i].data & ShadowMask; int layers = 4; + int shadow = ST_NONE; + + if (!lights[i].position[3]) { + shadow = ST_CASCADE; + } else { + if (lights[i].direction[3] > -0.5) { + shadow = ST_CUBE; + } else { + shadow = ST_PLANE; + } + } if (shadow != ST_CASCADE) { continue; @@ -902,9 +959,20 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) lctx->lightviews.a[i] = 0; continue; } + int mode = ST_NONE; + + if (!lctx->lights.a[i].position[3]) { + mode = ST_CASCADE; + } else { + if (lctx->lights.a[i].direction[3] > -0.5) { + mode = ST_CUBE; + } else { + mode = ST_PLANE; + } + } lctx->lightviews.a[i] = create_view (lctx->lightimages.a[imageMap[i]], lctx->lightlayers.a[i], - lctx->lights.a[i].data, i, ctx); + mode, i, ctx); } Sys_MaskPrintf (SYS_vulkan, "shadow maps: %d layers in %zd images: %zd\n", totalLayers, lctx->lightimages.size, memsize); @@ -932,6 +1000,7 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) } lctx->lights.size = 0; + lctx->lightstyles.size = 0; lctx->lightleafs.size = 0; lctx->lightmats.size = 0; if (lctx->sun_pvs) { @@ -989,11 +1058,13 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) parse_sun (lctx, entity, model); } else if (strnequal (classname, "light", 5)) { qfv_light_t light = {}; + int style = 0; - parse_light (&light, entity, targets); + parse_light (&light, &style, entity, targets); // some lights have 0 output, so drop them - if (light.light) { + if (light.color[3]) { DARRAY_APPEND (&lctx->lights, light); + DARRAY_APPEND (&lctx->lightstyles, style); } } } From e9ad7b748bb3e818c73c3c8e10919abf36d6d709 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 14:41:46 +0900 Subject: [PATCH 60/77] [renderer] Use scene_t to set the model data This replaces *_NewMap with *_NewScene and adds SCR_NewScene to handle loading a new map (for quake) in the renderer, and will eventually be how any new scene is loaded. --- include/QF/GL/qf_rmain.h | 4 ++-- include/QF/GLSL/qf_main.h | 3 ++- include/QF/Vulkan/qf_main.h | 4 ++-- include/QF/plugin/vid_render.h | 3 ++- include/QF/scene/scene.h | 3 +++ include/QF/screen.h | 3 +++ include/client/world.h | 1 - include/r_internal.h | 3 ++- include/r_local.h | 2 -- libs/client/cl_temp_entities.c | 6 +++--- libs/client/cl_world.c | 11 ++++++++--- libs/video/renderer/gl/gl_rmisc.c | 21 +++++++++++---------- libs/video/renderer/glsl/glsl_main.c | 11 ++++++----- libs/video/renderer/r_screen.c | 14 ++++++++++++++ libs/video/renderer/sw/sw_rmain.c | 4 +++- libs/video/renderer/vid_render_gl.c | 2 +- libs/video/renderer/vid_render_glsl.c | 2 +- libs/video/renderer/vid_render_sw.c | 2 +- libs/video/renderer/vid_render_vulkan.c | 7 ++++--- libs/video/renderer/vulkan/vulkan_main.c | 14 +++++++------- nq/source/cl_demo.c | 4 +++- nq/source/cl_ents.c | 6 +++--- nq/source/cl_main.c | 6 +++--- nq/source/cl_parse.c | 15 +++++++-------- nq/source/cl_screen.c | 5 +++-- nq/source/host.c | 3 ++- qw/source/cl_demo.c | 6 ++++-- qw/source/cl_entparse.c | 4 +++- qw/source/cl_ents.c | 12 ++++++------ qw/source/cl_main.c | 6 +++--- qw/source/cl_parse.c | 16 ++++++++-------- qw/source/cl_screen.c | 5 +++-- qw/source/sbar.c | 4 +++- qw/source/teamplay.c | 12 +++++++----- ruamoko/qwaq/builtins/graphics.c | 2 +- 35 files changed, 134 insertions(+), 92 deletions(-) diff --git a/include/QF/GL/qf_rmain.h b/include/QF/GL/qf_rmain.h index a9aea8770..85048cb05 100644 --- a/include/QF/GL/qf_rmain.h +++ b/include/QF/GL/qf_rmain.h @@ -45,8 +45,8 @@ void gl_R_RotateForEntity (struct entity_s *e); struct model_s; struct entqueue_s; -void gl_R_NewMap (struct model_s *worldmodel, struct model_s **models, - int num_models); +struct scene_s; +void gl_R_NewScene (struct scene_s *scene); void gl_R_RenderView (void); void gl_R_RenderEntities (struct entqueue_s *queue); void gl_R_ClearState (void); diff --git a/include/QF/GLSL/qf_main.h b/include/QF/GLSL/qf_main.h index b194805fb..621c0b2af 100644 --- a/include/QF/GLSL/qf_main.h +++ b/include/QF/GLSL/qf_main.h @@ -29,8 +29,9 @@ #define __QF_GLSL_qf_main_h struct entqueue_s; +struct scene_s; -void glsl_R_NewMap (model_t *worldmodel, model_t **models, int num_models); +void glsl_R_NewScene (struct scene_s *scene); void glsl_R_RenderEntities (struct entqueue_s *queue); void glsl_R_RenderView (void); void glsl_R_ClearState (void); diff --git a/include/QF/Vulkan/qf_main.h b/include/QF/Vulkan/qf_main.h index b52b0a7f3..8d2da31d6 100644 --- a/include/QF/Vulkan/qf_main.h +++ b/include/QF/Vulkan/qf_main.h @@ -31,9 +31,9 @@ struct vulkan_ctx_s; struct qfv_renderframe_s; struct entqueue_s; +struct scene_s; -void Vulkan_NewMap (model_t *worldmodel, struct model_s **models, - int num_models, struct vulkan_ctx_s *ctx); +void Vulkan_NewScene (struct scene_s *scene, struct vulkan_ctx_s *ctx); void Vulkan_RenderView (struct qfv_renderframe_s *rFrame); void Vulkan_RenderEntities (struct entqueue_s *queue, struct qfv_renderframe_s *rFrame); diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 0118df52f..1bcffe276 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -35,6 +35,7 @@ struct plitem_s; struct cvar_s; +struct scene_s; struct skin_s; struct mod_alias_ctx_s; @@ -105,7 +106,7 @@ typedef struct vid_render_funcs_s { void (*R_Init) (void); void (*R_ClearState) (void); void (*R_LoadSkys) (const char *); - void (*R_NewMap) (model_t *worldmodel, model_t **models, int num_models); + void (*R_NewScene) (struct scene_s *scene); void (*R_LineGraph) (int x, int y, int *h_vals, int count, int height); void (*begin_frame) (void); diff --git a/include/QF/scene/scene.h b/include/QF/scene/scene.h index b74c29955..66995bb9e 100644 --- a/include/QF/scene/scene.h +++ b/include/QF/scene/scene.h @@ -43,6 +43,9 @@ typedef struct scene_s { struct scene_resources_s *const resources; struct hierarchy_s *hierarchies; + struct model_s *worldmodel; + int num_models; + struct model_s **models; } scene_t; scene_t *Scene_NewScene (void); diff --git a/include/QF/screen.h b/include/QF/screen.h index 362cae41b..d53b1b1ee 100644 --- a/include/QF/screen.h +++ b/include/QF/screen.h @@ -29,6 +29,7 @@ #ifndef __QF_screen_h #define __QF_screen_h +struct scene_s; struct transform_s; struct tex_s; @@ -47,6 +48,8 @@ void SCR_SetFOV (float fov); void SCR_SetFullscreen (qboolean fullscreen); void SCR_SetBottomMargin (int lines); +void SCR_NewScene (struct scene_s *scene); + extern int hud_fps; extern int hud_time; extern int r_timegraph; diff --git a/include/client/world.h b/include/client/world.h index 191e313d8..ba67d9c35 100644 --- a/include/client/world.h +++ b/include/client/world.h @@ -43,7 +43,6 @@ typedef struct worldscene_s { struct scene_s *scene; struct plitem_s *edicts; struct plitem_s *worldspawn; - struct model_s *worldmodel; modelset_t models; } worldscene_t; diff --git a/include/r_internal.h b/include/r_internal.h index 8b43dac0a..2d8feccc4 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -45,7 +45,8 @@ struct psystem_s *glsl_ParticleSystem (void); struct psystem_s *sw_ParticleSystem (void); void R_RunParticles (float dT); -void R_NewMap (model_t *worldmodel, model_t **models, int num_models); +struct scene_s; +void R_NewScene (struct scene_s *scene); // LordHavoc: relative bmodel lighting void R_PushDlights (const vec3_t entorigin); diff --git a/include/r_local.h b/include/r_local.h index 486347f0d..4ea9d6795 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -202,8 +202,6 @@ extern void R_RotateBmodel (struct transform_s *transform); extern int c_faceclip; extern int r_polycount; -extern model_t *cl_worldmodel; - extern int *pfrustum_indexes[4]; // !!! if this is changed, it must be changed in asm_draw.h too !!! diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index 269a1c9ed..3be60f2bd 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -271,7 +271,7 @@ beam_setup (beam_t *b, qboolean transform, double time, TEntContext_t *ctx) } else { Transform_SetLocalPosition (tent->ent->transform, position); } - R_AddEfrags (&cl_world.worldmodel->brush, tent->ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, tent->ent); } } @@ -632,7 +632,7 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx) ent->animation.frame = f; if (!ent->visibility.efrag) { - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } } @@ -721,7 +721,7 @@ CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) angles[2] = 0; CL_TransformEntity (tent->ent, 1, angles, position); - R_AddEfrags (&cl_world.worldmodel->brush, tent->ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, tent->ent); } *tail = cl_projectiles; diff --git a/libs/client/cl_world.c b/libs/client/cl_world.c index 436013f79..63f92ff5b 100644 --- a/libs/client/cl_world.c +++ b/libs/client/cl_world.c @@ -119,7 +119,7 @@ CL_ParseStatic (qmsg_t *msg, int version) CL_TransformEntity (ent, es.scale / 16.0, es.angles, es.origin); - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } static void @@ -205,9 +205,14 @@ CL_LoadSky (const char *name) void CL_World_NewMap (const char *mapname, const char *skyname) { + model_t *worldmodel = cl_world.models.a[1]; + cl_world.scene->worldmodel = worldmodel; + cl_static_entities.size = 0; - r_funcs->R_NewMap (cl_world.worldmodel, - cl_world.models.a, cl_world.models.size); + + cl_world.scene->models = cl_world.models.a; + cl_world.scene->num_models = cl_world.models.size; + SCR_NewScene (cl_world.scene); if (cl_world.models.a[1] && cl_world.models.a[1]->brush.entities) { if (cl_world.edicts) { PL_Free (cl_world.edicts); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index f7056bcfb..681ca0771 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -66,6 +66,7 @@ #include "QF/GL/qf_vid.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "mod_internal.h" #include "r_internal.h" @@ -152,7 +153,7 @@ register_textures (mod_brush_t *brush) } void -gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) +gl_R_NewScene (scene_t *scene) { texture_t *tex; mod_brush_t *brush; @@ -160,8 +161,8 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) for (int i = 0; i < 256; i++) d_lightstylevalue[i] = 264; // normal light value - r_refdef.worldmodel = worldmodel; - brush = &worldmodel->brush; + r_refdef.worldmodel = scene->worldmodel; + brush = &scene->worldmodel->brush; // clear out efrags in case the level hasn't been reloaded for (unsigned i = 0; i < brush->modleafs; i++) @@ -173,7 +174,7 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) R_ClearParticles (); - GL_BuildLightmaps (models, num_models); + GL_BuildLightmaps (scene->models, scene->num_models); // identify sky texture gl_R_ClearTextures (); @@ -189,13 +190,13 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) gl_R_InitSurfaceChains (brush); gl_R_AddTexture (r_notexture_mip); register_textures (brush); - for (int i = 0; i < num_models; i++) { - if (!models[i]) + for (int i = 0; i < scene->num_models; i++) { + if (!scene->models[i]) continue; - if (*models[i]->path == '*') + if (*scene->models[i]->path == '*') continue; - if (models[i] != r_refdef.worldmodel - && models[i]->type == mod_brush) - register_textures (&models[i]->brush); + if (scene->models[i] != r_refdef.worldmodel + && scene->models[i]->type == mod_brush) + register_textures (&scene->models[i]->brush); } } diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index ba5ef36f2..5ea42af56 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -46,6 +46,7 @@ #include "QF/sys.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "QF/GLSL/defines.h" #include "QF/GLSL/funcs.h" @@ -188,23 +189,23 @@ glsl_R_Init (void) } void -glsl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) +glsl_R_NewScene (scene_t *scene) { int i; for (i = 0; i < 256; i++) d_lightstylevalue[i] = 264; // normal light value - r_refdef.worldmodel = worldmodel; + r_refdef.worldmodel = scene->worldmodel; // Force a vis update r_refdef.viewleaf = NULL; R_MarkLeaves (); R_ClearParticles (); - glsl_R_RegisterTextures (models, num_models); - glsl_R_BuildLightmaps (models, num_models); - glsl_R_BuildDisplayLists (models, num_models); + glsl_R_RegisterTextures (scene->models, scene->num_models); + glsl_R_BuildLightmaps (scene->models, scene->num_models); + glsl_R_BuildDisplayLists (scene->models, scene->num_models); } void diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 188b0ed93..a199fa368 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -49,6 +49,7 @@ #include "QF/va.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "QF/scene/transform.h" #include "QF/ui/view.h" @@ -71,6 +72,7 @@ static framebuffer_t *warp_buffer; static float fov_x, fov_y; static float tan_fov_x, tan_fov_y; +static scene_t *scr_scene;//FIXME don't want this here static mat4f_t box_rotations[] = { [BOX_FRONT] = { @@ -505,3 +507,15 @@ SCR_Init (void) Cvar_AddListener (var, viewsize_listener, 0); update_vrect (); } + +void +SCR_NewScene (scene_t *scene) +{ + scr_scene = scene; + if (scene) { + r_funcs->set_fov (tan_fov_x, tan_fov_y); + r_funcs->R_NewScene (scene); + } else { + r_funcs->R_ClearState (); + } +} diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index e05755a80..9bd3c3f1c 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -49,6 +49,7 @@ #include "QF/sys.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "compat.h" #include "mod_internal.h" @@ -151,8 +152,9 @@ sw_R_Init (void) } void -R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) +R_NewScene (scene_t *scene) { + model_t *worldmodel = scene->worldmodel; mod_brush_t *brush = &worldmodel->brush; r_refdef.worldmodel = worldmodel; diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index fa0c7738b..9d99ca43d 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -510,7 +510,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_R_Init, gl_R_ClearState, gl_R_LoadSkys, - gl_R_NewMap, + gl_R_NewScene, gl_R_LineGraph, gl_begin_frame, gl_render_view, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 4c4aff0d3..132e1f062 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -454,7 +454,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_R_Init, glsl_R_ClearState, glsl_R_LoadSkys, - glsl_R_NewMap, + glsl_R_NewScene, glsl_R_LineGraph, glsl_begin_frame, glsl_render_view, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 5d8c18f0c..a7d69ada7 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -474,7 +474,7 @@ vid_render_funcs_t sw_vid_render_funcs = { sw_R_Init, R_ClearState, R_LoadSkys, - R_NewMap, + R_NewScene, R_LineGraph, sw_begin_frame, sw_render_view, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 424363571..a52e3b7eb 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -64,6 +64,7 @@ #include "QF/ui/view.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "mod_internal.h" #include "r_internal.h" @@ -118,9 +119,9 @@ vulkan_R_LoadSkys (const char *skyname) } static void -vulkan_R_NewMap (model_t *worldmodel, model_t **models, int num_models) +vulkan_R_NewScene (scene_t *scene) { - Vulkan_NewMap (worldmodel, models, num_models, vulkan_ctx); + Vulkan_NewScene (scene, vulkan_ctx); } static void @@ -727,7 +728,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_R_Init, vulkan_R_ClearState, vulkan_R_LoadSkys, - vulkan_R_NewMap, + vulkan_R_NewScene, vulkan_R_LineGraph, vulkan_begin_frame, vulkan_render_view, diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 6acf30d09..17c74ec6b 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -46,6 +46,7 @@ #include "QF/sys.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/qf_alias.h" @@ -130,8 +131,7 @@ Vulkan_RenderView (qfv_renderframe_t *rFrame) } void -Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, - vulkan_ctx_t *ctx) +Vulkan_NewScene (scene_t *scene, vulkan_ctx_t *ctx) { int i; @@ -139,17 +139,17 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, d_lightstylevalue[i] = 264; // normal light value } - r_refdef.worldmodel = worldmodel; + r_refdef.worldmodel = scene->worldmodel; // Force a vis update r_refdef.viewleaf = NULL; R_MarkLeaves (); R_ClearParticles (); - Vulkan_RegisterTextures (models, num_models, ctx); - //Vulkan_BuildLightmaps (models, num_models, ctx); - Vulkan_BuildDisplayLists (models, num_models, ctx); - Vulkan_LoadLights (worldmodel, worldmodel->brush.entities, ctx); + Vulkan_RegisterTextures (scene->models, scene->num_models, ctx); + //Vulkan_BuildLightmaps (scene->models, scene->num_models, ctx); + Vulkan_BuildDisplayLists (scene->models, scene->num_models, ctx); + Vulkan_LoadLights (scene->worldmodel, scene->worldmodel->brush.entities, ctx); } /*void diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index 510ea767c..538ed10bf 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -46,6 +46,8 @@ #include "QF/sys.h" #include "QF/va.h" +#include "QF/scene/scene.h" + #include "compat.h" #include "client/world.h" @@ -375,7 +377,7 @@ demo_default_name (const char *argv1) strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); // the leading path-name is to be removed from cl_world.worldmodel->name - mapname = QFS_SkipPath (cl_world.worldmodel->path); + mapname = QFS_SkipPath (cl_world.scene->worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 9d0a4d357..cdfbe644d 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -263,7 +263,7 @@ CL_RelinkEntities (void) if (ent->visibility.efrag) { R_RemoveEfrags (ent); } - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } ent->old_origin = new->origin; } else { @@ -299,10 +299,10 @@ CL_RelinkEntities (void) = Transform_GetWorldPosition (ent->transform); if (!VectorCompare (org, ent->old_origin)) {//FIXME R_RemoveEfrags (ent); - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } else { - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } } diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index e05d98c7d..0d3f0864f 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -295,7 +295,7 @@ CL_ClearState (void) CL_ClearTEnts (); - r_funcs->R_ClearState (); + SCR_NewScene (0); CL_ClearEnts (); @@ -354,7 +354,7 @@ CL_Disconnect (void) Host_ShutdownServer (false); } - cl_world.worldmodel = NULL; + cl_world.scene->worldmodel = NULL; cl.intermission = 0; cl.viewstate.intermission = 0; } @@ -467,7 +467,7 @@ CL_NextDemo (void) static void pointfile_f (void) { - CL_LoadPointFile (cl_world.worldmodel); + CL_LoadPointFile (cl_world.scene->worldmodel); } static void diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index b9c1f0ac6..db35c61fd 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -252,10 +252,13 @@ CL_KeepaliveMessage (void) static void CL_NewMap (const char *mapname) { - Con_NewMap (); - Hunk_Check (0); // make sure nothing is hurt - Sbar_CenterPrint (0); CL_World_NewMap (mapname, 0); + cl.chasestate.worldmodel = cl_world.scene->worldmodel; + + Con_NewMap (); + Sbar_CenterPrint (0); + + Hunk_Check (0); // make sure nothing is hurt } static void @@ -349,9 +352,9 @@ CL_ParseServerInfo (void) strcpy (sound_precache[cl.numsounds], str); } - // now we try to load everything else until a cache allocation fails CL_MapCfg (model_precache[1]); + // now we try to load everything else until a cache allocation fails for (i = 1; i < nummodels; i++) { DARRAY_APPEND (&cl_world.models, Mod_ForName (model_precache[i], false)); @@ -368,16 +371,12 @@ CL_ParseServerInfo (void) } // local state - cl_world.worldmodel = cl_world.models.a[1]; - cl.chasestate.worldmodel = cl_world.worldmodel; if (!centerprint) centerprint = dstring_newstr (); else dstring_clearstr (centerprint); CL_NewMap (model_precache[1]); - Hunk_Check (0); // make sure nothing is hurt - noclip_anglehack = false; // noclip is turned off at start CL_ParticlesGravity (800); // Set up gravity for renderer effects done: diff --git a/nq/source/cl_screen.c b/nq/source/cl_screen.c index 4bbb1f9dd..bd2effd81 100644 --- a/nq/source/cl_screen.c +++ b/nq/source/cl_screen.c @@ -46,6 +46,7 @@ #include "QF/plugin/vid_render.h" +#include "QF/scene/scene.h" #include "QF/scene/transform.h" #include "QF/ui/view.h" @@ -79,10 +80,10 @@ SCR_CShift (void) mleaf_t *leaf; int contents = CONTENTS_EMPTY; - if (cls.state == ca_active && cl_world.worldmodel) { + if (cls.state == ca_active && cl_world.scene->worldmodel) { vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - leaf = Mod_PointInLeaf ((vec_t*)&origin, cl_world.worldmodel);//FIXME + leaf = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME contents = leaf->contents; } V_SetContentsColor (&cl.viewstate, contents); diff --git a/nq/source/host.c b/nq/source/host.c index ca58afed5..b1cade921 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -54,6 +54,7 @@ #include "QF/plugin/console.h" #include "QF/plugin/vid_render.h" +#include "QF/scene/scene.h" #include "QF/scene/transform.h" #include "buildnum.h" @@ -740,7 +741,7 @@ Host_ClientFrame (void) vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - l = Mod_PointInLeaf ((vec_t*)&origin, cl_world.worldmodel);//FIXME + l = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME if (l) asl = l->ambient_sound_level; S_Update (cl.viewstate.camera_transform, asl); diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index c7ede77e3..0026b72f5 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -54,6 +54,8 @@ #include "QF/sys.h" #include "QF/va.h" +#include "QF/scene/scene.h" + #include "compat.h" #include "client/world.h" @@ -669,8 +671,8 @@ demo_default_name (const char *argv1) time (&tim); strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); - // the leading path-name is to be removed from cl_world.worldmodel->name - mapname = QFS_SkipPath (cl_world.worldmodel->path); + // the leading path-name is to be removed from worldmodel->name + mapname = QFS_SkipPath (cl_world.scene->worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index 26486ae41..d9ada8aa8 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -41,6 +41,8 @@ #include "QF/skin.h" #include "QF/sys.h" +#include "QF/scene/scene.h" + #include "compat.h" #include "client/temp_entities.h" @@ -530,7 +532,7 @@ CL_SetSolidEntities (void) frame_t *frame; packet_entities_t *pak; - pmove.physents[0].model = cl_world.worldmodel; + pmove.physents[0].model = cl_world.scene->worldmodel; VectorZero (pmove.physents[0].origin); VectorZero (pmove.physents[0].angles); pmove.physents[0].info = 0; diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index a4955c409..49ad77cc1 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -234,7 +234,7 @@ CL_LinkPacketEntities (void) if (ent->visibility.efrag) { R_RemoveEfrags (ent); } - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } else { vec4f_t delta = new->origin - old->origin; @@ -266,15 +266,15 @@ CL_LinkPacketEntities (void) = Transform_GetWorldPosition (ent->transform); if (!VectorCompare (org, ent->old_origin)) {//FIXME R_RemoveEfrags (ent); - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } else { - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } } if (!ent->visibility.efrag) { - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } // rotate binary objects locally @@ -510,10 +510,10 @@ CL_LinkPlayers (void) } // stuff entity in map - R_AddEfrags (&cl_world.worldmodel->brush, ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); if (player->flag_ent) { CL_UpdateFlagModels (ent, j); - R_AddEfrags (&cl_world.worldmodel->brush, player->flag_ent); + R_AddEfrags (&cl_world.scene->worldmodel->brush, player->flag_ent); } } } diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index bdb2ac24a..668208e6c 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -501,7 +501,7 @@ CL_Quit_f (void) static void pointfile_f (void) { - CL_LoadPointFile (cl_world.worldmodel); + CL_LoadPointFile (cl_world.scene->worldmodel); } static void @@ -794,7 +794,7 @@ CL_Disconnect (void) Info_Destroy (cl.players[i].userinfo); memset (&cl.players[i], 0, sizeof (cl.players[i])); } - cl_world.worldmodel = NULL; + cl_world.scene->worldmodel = NULL; cl.validsequence = 0; } @@ -1965,7 +1965,7 @@ Host_Frame (float time) vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - l = Mod_PointInLeaf ((vec_t*)&origin, cl_world.worldmodel);//FIXME + l = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME if (l) asl = l->ambient_sound_level; S_Update (cl.viewstate.camera_transform, asl); diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 5b58202ac..fa3c2075f 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -261,17 +261,19 @@ CL_CheckOrDownloadFile (const char *filename) static void CL_NewMap (const char *mapname) { - Team_NewMap (); - Con_NewMap (); - Hunk_Check (0); // make sure nothing is hurt - Sbar_CenterPrint (0); - const char *skyname = 0; // R_LoadSkys does the right thing with null pointers. if (cl.serverinfo) { skyname = Info_ValueForKey (cl.serverinfo, "sky"); } CL_World_NewMap (mapname, skyname); + cl.chasestate.worldmodel = cl_world.scene->worldmodel; + + Team_NewMap (); + Con_NewMap (); + Sbar_CenterPrint (0); + + Hunk_Check (0); // make sure nothing is hurt } static void @@ -353,8 +355,6 @@ Model_NextDownload (void) } // all done - cl_world.worldmodel = cl_world.models.a[1]; - cl.chasestate.worldmodel = cl_world.worldmodel; CL_NewMap (cl.model_name[1]); // done with modellist, request first of static signon messages @@ -362,7 +362,7 @@ Model_NextDownload (void) MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, va (0, prespawn_name, cl.servercount, - cl_world.worldmodel->brush.checksum2)); + cl_world.scene->worldmodel->brush.checksum2)); } } diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index 82fd9b63d..54871dac5 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -44,6 +44,7 @@ #include "QF/pcx.h" #include "QF/screen.h" +#include "QF/scene/scene.h" #include "QF/scene/transform.h" #include "QF/ui/view.h" @@ -78,10 +79,10 @@ SCR_CShift (void) mleaf_t *leaf; int contents = CONTENTS_EMPTY; - if (cls.state == ca_active && cl_world.worldmodel) { + if (cls.state == ca_active && cl_world.scene->worldmodel) { vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - leaf = Mod_PointInLeaf ((vec_t*)&origin, cl_world.worldmodel);//FIXME + leaf = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME contents = leaf->contents; } V_SetContentsColor (&cl.viewstate, contents); diff --git a/qw/source/sbar.c b/qw/source/sbar.c index ebc9d267e..d016aeb11 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -53,6 +53,8 @@ #include "QF/plugin/console.h" +#include "QF/scene/scene.h" + #include "QF/ui/view.h" #include "compat.h" @@ -1062,7 +1064,7 @@ Sbar_LogFrags (void) Qwrite (file, t, strlen (t)); Qprintf (file, "%s\n%s %s\n", cls.servername->str, - cl_world.worldmodel->path, cl.levelname); + cl_world.scene->worldmodel->path, cl.levelname); // scores Sbar_SortFrags (true); diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index 926093007..5bca2f58d 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -49,6 +49,8 @@ #include "QF/sys.h" #include "QF/teamplay.h" +#include "QF/scene/scene.h" + #include "compat.h" #include "client/locs.h" @@ -332,8 +334,8 @@ Team_NewMap (void) died = false; recorded_location = false; - mapname = strdup (cl_world.worldmodel->path); - t2 = malloc (sizeof (cl_world.worldmodel->path)); + mapname = strdup (cl_world.scene->worldmodel->path); + t2 = malloc (sizeof (cl_world.scene->worldmodel->path)); if (!mapname || !t2) Sys_Error ("Can't duplicate mapname!"); map_to_loc (mapname,t2); @@ -376,16 +378,16 @@ locs_loc (void) "parameter\n"); return; } - if (!cl_world.worldmodel) { + if (!cl_world.scene->worldmodel) { Sys_Printf ("No map loaded. Unable to work with location markers.\n"); return; } if (Cmd_Argc () >= 3) desc = Cmd_Args (2); - mapname = malloc (sizeof (cl_world.worldmodel->path)); + mapname = malloc (sizeof (cl_world.scene->worldmodel->path)); if (!mapname) Sys_Error ("Can't duplicate mapname!"); - map_to_loc (cl_world.worldmodel->path, mapname); + map_to_loc (cl_world.scene->worldmodel->path, mapname); snprintf (locfile, sizeof (locfile), "%s/%s", qfs_gamedir->dir.def, mapname); free (mapname); diff --git a/ruamoko/qwaq/builtins/graphics.c b/ruamoko/qwaq/builtins/graphics.c index 0e272a07a..6b1737906 100644 --- a/ruamoko/qwaq/builtins/graphics.c +++ b/ruamoko/qwaq/builtins/graphics.c @@ -233,5 +233,5 @@ BI_Graphics_Init (progs_t *pr) if (mod_funcs->Mod_ProcessTexture) { mod_funcs->Mod_ProcessTexture (&empty_world, 0); } - r_funcs->R_NewMap (&empty_world, 0, 0); + //r_funcs->R_NewMap (&empty_world, 0, 0); } From 9ee0eada1f462ce1f6c0e91948148949f6611e70 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 14:58:47 +0900 Subject: [PATCH 61/77] [vulkan] Move non-specific lighting code out of Vulkan The parsing of light data from maps is now in the client library, and basic light management is in scene. Putting the light loading code into the Vulkan renderer was a mistake I've wanted to correct for a while. The client code still needs a bit of cleanup, but the basics are working nicely. --- include/QF/Makemodule.am | 1 + include/QF/Vulkan/qf_lighting.h | 39 +- include/QF/render.h | 1 - include/QF/scene/light.h | 80 ++++ include/QF/scene/scene.h | 2 + include/QF/sys_developer.h | 1 + include/client/world.h | 3 + include/r_internal.h | 2 +- libs/client/Makemodule.am | 1 + libs/client/cl_light.c | 320 +++++++++++++ libs/client/cl_world.c | 5 + libs/scene/Makemodule.am | 1 + libs/scene/light.c | 140 ++++++ libs/video/renderer/gl/gl_rmisc.c | 3 +- libs/video/renderer/glsl/glsl_main.c | 3 +- libs/video/renderer/r_bsp.c | 10 +- libs/video/renderer/r_screen.c | 11 +- libs/video/renderer/sw/sw_rmain.c | 3 +- libs/video/renderer/vulkan/vulkan_lighting.c | 458 ++----------------- libs/video/renderer/vulkan/vulkan_main.c | 5 +- 20 files changed, 609 insertions(+), 480 deletions(-) create mode 100644 include/QF/scene/light.h create mode 100644 libs/client/cl_light.c create mode 100644 libs/scene/light.c diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index c9783b4fa..7c255e882 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -149,6 +149,7 @@ include_qf_scene = \ include/QF/scene/camera.h \ include/QF/scene/entity.h \ include/QF/scene/hierarchy.h \ + include/QF/scene/light.h \ include/QF/scene/transform.h \ include/QF/scene/scene.h \ include/QF/scene/types.h diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index f8b6e5d84..ef6a6bb24 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -33,41 +33,23 @@ #include "QF/darray.h" #include "QF/model.h" #include "QF/modelgen.h" +#include "QF/scene/light.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/image.h" #include "QF/simd/types.h" -typedef struct qfv_light_s { - vec4f_t color; - vec4f_t position; - vec4f_t direction; - vec4f_t attenuation; -} qfv_light_t; - -typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t; -typedef struct qfv_lightleafset_s DARRAY_TYPE (int) qfv_lightintset_t; -typedef struct qfv_lightvisset_s DARRAY_TYPE (byte) qfv_lightvisset_t; typedef struct qfv_lightmatset_s DARRAY_TYPE (mat4f_t) qfv_lightmatset_t; #define MaxLights 256 -#define LM_LINEAR 0 // light - dist (or radius + dist if -ve) -#define LM_INVERSE 1 // distFactor1 * light / dist -#define LM_INVERSE2 2 // distFactor2 * light / (dist * dist) -#define LM_INFINITE 3 // light -#define LM_AMBIENT 4 // light -#define LM_INVERSE3 5 // distFactor2 * light / (dist + distFactor2)**2 - #define ST_NONE 0 // no shadows #define ST_PLANE 1 // single plane shadow map (small spotlight) #define ST_CASCADE 2 // cascaded shadow maps #define ST_CUBE 3 // cubemap (omni, large spotlight) -#define NumStyles 64 - typedef struct qfv_light_buffer_s { - qfv_light_t lights[MaxLights] __attribute__((aligned(16))); + light_t lights[MaxLights] __attribute__((aligned(16))); int lightCount; //mat4f_t shadowMat[MaxLights]; //vec4f_t shadowCascade[MaxLights]; @@ -92,11 +74,6 @@ typedef struct lightingframe_s { VkWriteDescriptorSet shadowWrite; }; }; - // A fat PVS of leafs visible from visible leafs so hidden lights can - // illuminate the leafs visible to the player - struct set_s *pvs; - struct mleaf_s *leaf; // the last leaf used to generate the pvs - qfv_lightvisset_t lightvis; } lightingframe_t; typedef struct lightingframeset_s @@ -109,14 +86,13 @@ typedef struct lightingctx_s { VkSampler sampler; VkDeviceMemory light_memory; VkDeviceMemory shadow_memory; - qfv_lightset_t lights; - qfv_lightintset_t lightstyles; - qfv_lightintset_t lightleafs; qfv_lightmatset_t lightmats; qfv_imageset_t lightimages; - qfv_lightintset_t lightlayers; + lightintset_t lightlayers; qfv_imageviewset_t lightviews; - struct set_s *sun_pvs; + + struct lightingdata_s *ldata; + struct scene_s *scene; } lightingctx_t; struct vulkan_ctx_s; @@ -125,7 +101,6 @@ struct qfv_renderframe_s; void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx); void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx); void Vulkan_Lighting_Draw (struct qfv_renderframe_s *rFrame); -void Vulkan_LoadLights (model_t *model, const char *entity_data, - struct vulkan_ctx_s *ctx); +void Vulkan_LoadLights (struct scene_s *scene, struct vulkan_ctx_s *ctx); #endif//__QF_Vulkan_qf_lighting_h diff --git a/include/QF/render.h b/include/QF/render.h index 01994d095..9ad381c89 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -167,7 +167,6 @@ typedef struct { int drawflat; struct model_s *worldmodel; - struct mleaf_s *viewleaf; } refdef_t; // REFRESH ==================================================================== diff --git a/include/QF/scene/light.h b/include/QF/scene/light.h new file mode 100644 index 000000000..4c6845c20 --- /dev/null +++ b/include/QF/scene/light.h @@ -0,0 +1,80 @@ +/* + light.h + + Entity management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/02/26 + + 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 + +*/ + +#ifndef __QF_scene_light_h +#define __QF_scene_light_h + +#include "QF/darray.h" +#include "QF/qtypes.h" +#include "QF/simd/types.h" + +struct mod_brush_s; + +#define NumStyles 64 +#define NoStyle -1 + +#define LM_LINEAR 0 // light - dist (or radius + dist if -ve) +#define LM_INVERSE 1 // distFactor1 * light / dist +#define LM_INVERSE2 2 // distFactor2 * light / (dist * dist) +#define LM_INFINITE 3 // light +#define LM_AMBIENT 4 // light +#define LM_INVERSE3 5 // distFactor2 * light / (dist + distFactor2)**2 + +typedef struct light_s { + vec4f_t color; + vec4f_t position; + vec4f_t direction; + vec4f_t attenuation; +} light_t; + +typedef struct lightset_s DARRAY_TYPE (light_t) lightset_t; +typedef struct lightleafset_s DARRAY_TYPE (int) lightintset_t; +typedef struct lightvisset_s DARRAY_TYPE (byte) lightvisset_t; + +typedef struct lightingdata_s { + lightset_t lights; + lightintset_t lightstyles; + lightintset_t lightleafs; + lightvisset_t lightvis; + struct set_s *sun_pvs; + // A fat PVS of leafs visible from visible leafs so hidden lights can + // illuminate the leafs visible to the player + struct set_s *pvs; + struct mleaf_s *leaf; // the last leaf used to generate the pvs + struct scene_s *scene; +} lightingdata_t; + +lightingdata_t *Light_CreateLightingData (struct scene_s *scene); +void Light_DestroyLightingData (lightingdata_t *ldata); +void Light_ClearLights (lightingdata_t *ldata); +void Light_EnableSun (lightingdata_t *ldata); +void Light_FindVisibleLights (lightingdata_t *ldata); + +#endif//__QF_scene_light_h diff --git a/include/QF/scene/scene.h b/include/QF/scene/scene.h index 66995bb9e..ec95221a2 100644 --- a/include/QF/scene/scene.h +++ b/include/QF/scene/scene.h @@ -46,6 +46,8 @@ typedef struct scene_s { struct model_s *worldmodel; int num_models; struct model_s **models; + struct mleaf_s *viewleaf; + struct lightingdata_s *lights; } scene_t; scene_t *Scene_NewScene (void); diff --git a/include/QF/sys_developer.h b/include/QF/sys_developer.h index 3dd3ba303..881742430 100644 --- a/include/QF/sys_developer.h +++ b/include/QF/sys_developer.h @@ -44,6 +44,7 @@ SYS_DEVELOPER (glt) SYS_DEVELOPER (glsl) SYS_DEVELOPER (skin) SYS_DEVELOPER (model) +SYS_DEVELOPER (lighting) SYS_DEVELOPER (vulkan) SYS_DEVELOPER (vulkan_parse) diff --git a/include/client/world.h b/include/client/world.h index ba67d9c35..e96ec48e3 100644 --- a/include/client/world.h +++ b/include/client/world.h @@ -50,6 +50,7 @@ extern worldscene_t cl_world; struct msg_s; struct entity_state_s; +struct lightingdata_s; void CL_World_Init (void); @@ -65,5 +66,7 @@ void CL_ParseBaseline (struct msg_s *msg, struct entity_state_s *baseline, void CL_ParseStatic (struct msg_s *msg, int version); void CL_MapCfg (const char *mapname); void CL_World_NewMap (const char *mapname, const char *skyname); +void CL_LoadLights (struct model_s *model, const char *entity_data, + struct lightingdata_s *ldata); #endif//__client_world_h diff --git a/include/r_internal.h b/include/r_internal.h index 2d8feccc4..95a1c26bc 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -74,7 +74,7 @@ struct entity_s; struct animation_s; void R_DrawAliasModel (struct entity_s *e); -void R_MarkLeaves (void); +void R_MarkLeaves (struct mleaf_s *viewleaf); void GL_SetPalette (void *data, const byte *palette); void GLSL_SetPalette (void *data, const byte *palette); diff --git a/libs/client/Makemodule.am b/libs/client/Makemodule.am index 95664df07..92d058458 100644 --- a/libs/client/Makemodule.am +++ b/libs/client/Makemodule.am @@ -7,6 +7,7 @@ libs_client_libQFclient_la_SOURCES= \ libs/client/cl_effects.c \ libs/client/cl_entities.c \ libs/client/cl_input.c \ + libs/client/cl_light.c \ libs/client/cl_particles.c \ libs/client/cl_temp_entities.c \ libs/client/cl_view.c \ diff --git a/libs/client/cl_light.c b/libs/client/cl_light.c new file mode 100644 index 000000000..8aa9cb39c --- /dev/null +++ b/libs/client/cl_light.c @@ -0,0 +1,320 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/model.h" +#include "QF/plist.h" +#include "QF/progs.h" //for ED_ConvertToPlist +#include "QF/script.h" +#include "QF/set.h" +#include "QF/scene/light.h" +#include "QF/simd/vec4f.h" + +#include "client/world.h" + +static void +dump_light (light_t *light, int leaf) +{ + Sys_MaskPrintf (SYS_lighting, + "[%g, %g, %g] %g, " + "[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n", + VEC4_EXP (light->color), + VEC4_EXP (light->position), + VEC4_EXP (light->direction), + VEC4_EXP (light->attenuation), + leaf); +} + +static float +parse_float (const char *str, float defval) +{ + float val = defval; + if (str) { + char *end; + val = strtof (str, &end); + if (end == str) { + val = defval; + } + } + return val; +} + +static void +parse_vector (const char *str, vec_t *val) +{ + if (str) { + int num = sscanf (str, "%f %f %f", VectorExpandAddr (val)); + while (num < 3) { + val[num++] = 0; + } + } +} + +static float +ecos (float ang) +{ + if (ang == 90 || ang == -90) { + return 0; + } + if (ang == 180 || ang == -180) { + return -1; + } + if (ang == 0 || ang == 360) { + return 1; + } + return cos (ang * M_PI / 180); +} + +static float +esin (float ang) +{ + if (ang == 90) { + return 1; + } + if (ang == -90) { + return -1; + } + if (ang == 180 || ang == -180) { + return 0; + } + if (ang == 0 || ang == 360) { + return 0; + } + return sin (ang * M_PI / 180); +} + +static vec4f_t +sun_vector (const vec_t *ang) +{ + // ang is yaw, pitch (maybe roll, but ignored + vec4f_t vec = { + ecos (ang[1]) * ecos (ang[0]), + ecos (ang[1]) * esin (ang[0]), + esin (ang[1]), + 0, + }; + return vec; +} + +static void +parse_sun (lightingdata_t *ldata, plitem_t *entity) +{ + light_t light = {}; + float sunlight; + //float sunlight2; + vec3_t sunangle = { 0, -90, 0 }; + + Light_EnableSun (ldata); + sunlight = parse_float (PL_String (PL_ObjectForKey (entity, + "_sunlight")), 0); + //sunlight2 = parse_float (PL_String (PL_ObjectForKey (entity, + // "_sunlight2")), 0); + parse_vector (PL_String (PL_ObjectForKey (entity, "_sun_mangle")), + sunangle); + if (sunlight <= 0) { + return; + } + VectorSet (1, 1, 1, light.color); + light.color[3] = sunlight; + light.position = sun_vector (sunangle); + light.direction = light.position; + light.direction[3] = 1; + light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; + DARRAY_APPEND (&ldata->lights, light); + DARRAY_APPEND (&ldata->lightstyles, 0); + DARRAY_APPEND (&ldata->lightleafs, -1); +} + +static vec4f_t +parse_position (const char *str) +{ + vec3_t vec = {}; + sscanf (str, "%f %f %f", VectorExpandAddr (vec)); + return (vec4f_t) {vec[0], vec[1], vec[2], 1}; +} + +static void +parse_light (light_t *light, int *style, const plitem_t *entity, + const plitem_t *targets) +{ + const char *str; + int model = 0; + + /*Sys_Printf ("{\n"); + for (int i = PL_D_NumKeys (entity); i-- > 0; ) { + const char *field = PL_KeyAtIndex (entity, i); + const char *value = PL_String (PL_ObjectForKey (entity, field)); + Sys_Printf ("\t%s = %s\n", field, value); + } + Sys_Printf ("}\n");*/ + + // omnidirectional light (unit length xyz so not treated as ambient) + light->direction = (vec4f_t) { 0, 0, 1, 1 }; + // bright white + light->color = (vec4f_t) { 1, 1, 1, 300 }; + + if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { + light->position = parse_position (str); + } + + if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { + plitem_t *target = PL_ObjectForKey (targets, str); + vec4f_t dir = { 1, 0, 0, 0 }; + if (target) { + if ((str = PL_String (PL_ObjectForKey (target, "origin")))) { + dir = parse_position (str); + dir = normalf (dir - light->position); + } + } + + float angle = 40; + if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) { + angle = atof (str); + } + dir[3] = -cos (angle * M_PI / 360); // half angle + light->direction = dir; + } + + if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) + || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { + light->color[3] = atof (str); + } + + if ((str = PL_String (PL_ObjectForKey (entity, "style")))) { + *style = atoi (str) & 0x3f; + } + + if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) { + model = atoi (str) & 0x7; + if (model == LM_INVERSE2) { + model = LM_INVERSE3; //FIXME for marcher (need a map) + } + } + + if ((str = PL_String (PL_ObjectForKey (entity, "color"))) + || (str = PL_String (PL_ObjectForKey (entity, "_color")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (light->color)); + VectorScale (light->color, 1/255.0, light->color); + } + + vec4f_t attenuation = { 1, 0, 0, 0 }; // inverse square + switch (model) { + case LM_LINEAR: + attenuation = (vec4f_t) { 0, 0, 1, 1 / fabsf (light->color[3]) }; + break; + case LM_INVERSE: + attenuation = (vec4f_t) { 0, 1.0 / 128, 0, 0 }; + break; + case LM_INVERSE2: + attenuation = (vec4f_t) { 1.0 / 16384, 0, 0, 0 }; + break; + case LM_INFINITE: + attenuation = (vec4f_t) { 0, 0, 1, 0 }; + break; + case LM_AMBIENT: + attenuation = (vec4f_t) { 0, 0, 1, 0 }; + light->direction = (vec4f_t) { 0, 0, 0, 1 }; + break; + case LM_INVERSE3: + attenuation = (vec4f_t) { 1.0 / 16384, 2.0 / 128, 1, 0 }; + break; + } + light->attenuation = attenuation; +} + +static void +locate_lights (model_t *model, lightingdata_t *ldata) +{ + light_t *lights = ldata->lights.a; + DARRAY_RESIZE (&ldata->lightleafs, ldata->lights.size); + for (size_t i = 0; i < ldata->lights.size; i++) { + mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model); + ldata->lightleafs.a[i] = leaf - model->brush.leafs - 1; + } +} + +void +CL_LoadLights (model_t *model, const char *entity_data, lightingdata_t *ldata) +{ + plitem_t *entities = 0; + + if (!entity_data) { + return; + } + + Light_ClearLights (ldata); + + ldata->sun_pvs = set_new_size (model->brush.visleafs); + + script_t *script = Script_New (); + Script_Start (script, "ent data", entity_data); + + if (Script_GetToken (script, 1)) { + if (!strcmp (script->token->str, "(")) { + // new style (plist) entity data + entities = PL_GetPropertyList (entity_data, 0); + } else { + // old style entity data + Script_UngetToken (script); + // FIXME ED_ConvertToPlist aborts if an error is encountered. + entities = ED_ConvertToPlist (script, 0, 0); + } + } + Script_Delete (script); + + if (entities) { + plitem_t *targets = PL_NewDictionary (0); + + // find all the targets so spotlights can be aimed + for (int i = 1; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *targetname = PL_String (PL_ObjectForKey (entity, + "targetname")); + if (targetname && !PL_ObjectForKey (targets, targetname)) { + PL_D_AddObject (targets, targetname, entity); + } + } + + for (int i = 0; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *classname = PL_String (PL_ObjectForKey (entity, + "classname")); + if (!classname) { + continue; + } + if (!strcmp (classname, "worldspawn")) { + // parse_sun can add many lights + parse_sun (ldata, entity); + } else if (!strncmp (classname, "light", 5)) { + light_t light = {}; + int style = 0; + + parse_light (&light, &style, entity, targets); + // some lights have 0 output, so drop them + if (light.color[3]) { + DARRAY_APPEND (&ldata->lights, light); + DARRAY_APPEND (&ldata->lightstyles, style); + } + } + } + DARRAY_RESIZE (&ldata->lightvis, ldata->lights.size); + // targets does not own the objects, so need to remove them before + // freeing targets + for (int i = PL_D_NumKeys (targets); i-- > 0; ) { + PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i)); + } + PL_Free (targets); + PL_Free (entities); + } + if (ldata->lights.size) { + locate_lights (model, ldata); + for (size_t i = 0; i < ldata->lights.size; i++) { + dump_light (&ldata->lights.a[i], ldata->lightleafs.a[i]); + } + } + Sys_MaskPrintf (SYS_lighting, "loaded %zd lights\n", ldata->lights.size); +} diff --git a/libs/client/cl_world.c b/libs/client/cl_world.c index 63f92ff5b..1bcb256fa 100644 --- a/libs/client/cl_world.c +++ b/libs/client/cl_world.c @@ -47,6 +47,7 @@ #include "QF/msg.h" #include "QF/scene/entity.h" +#include "QF/scene/light.h" #include "QF/scene/scene.h" #include "QF/simd/vec4f.h" @@ -64,6 +65,7 @@ void CL_World_Init (void) { cl_world.scene = Scene_NewScene (); + cl_world.scene->lights = Light_CreateLightingData (cl_world.scene); } void @@ -210,6 +212,9 @@ CL_World_NewMap (const char *mapname, const char *skyname) cl_static_entities.size = 0; + const char *entity_data = worldmodel->brush.entities; + CL_LoadLights (worldmodel, entity_data, cl_world.scene->lights); + cl_world.scene->models = cl_world.models.a; cl_world.scene->num_models = cl_world.models.size; SCR_NewScene (cl_world.scene); diff --git a/libs/scene/Makemodule.am b/libs/scene/Makemodule.am index 25b3e7562..13cfb6dca 100644 --- a/libs/scene/Makemodule.am +++ b/libs/scene/Makemodule.am @@ -11,5 +11,6 @@ libs_scene_libQFscene_la_SOURCES= \ libs/scene/camera.c \ libs/scene/entity.c \ libs/scene/hierarchy.c \ + libs/scene/light.c \ libs/scene/scene.c \ libs/scene/transform.c diff --git a/libs/scene/light.c b/libs/scene/light.c new file mode 100644 index 000000000..fc38e71af --- /dev/null +++ b/libs/scene/light.c @@ -0,0 +1,140 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "QF/model.h" +#include "QF/set.h" +#include "QF/scene/light.h" +#include "QF/scene/scene.h" +#include "QF/simd/vec4f.h" + +static void +expand_pvs (set_t *pvs, model_t *model) +{ + set_t base_pvs = SET_STATIC_INIT (model->brush.visleafs, alloca); + set_assign (&base_pvs, pvs); + for (unsigned i = 0; i < model->brush.visleafs; i++) { + if (set_is_member (&base_pvs, i)) { + Mod_LeafPVS_mix (model->brush.leafs + i + 1, model, 0, pvs); + } + } +} + +lightingdata_t * +Light_CreateLightingData (scene_t *scene) +{ + lightingdata_t *ldata = calloc (1, sizeof (lightingdata_t)); + + DARRAY_INIT (&ldata->lights, 16); + DARRAY_INIT (&ldata->lightstyles, 16); + DARRAY_INIT (&ldata->lightleafs, 16); + DARRAY_INIT (&ldata->lightvis, 16); + + ldata->scene = scene; + + return ldata; +} + +void +Light_DestroyLightingData (lightingdata_t *ldata) +{ + DARRAY_CLEAR (&ldata->lights); + DARRAY_CLEAR (&ldata->lightstyles); + DARRAY_CLEAR (&ldata->lightleafs); + DARRAY_CLEAR (&ldata->lightvis); + + free (ldata); +} + +void +Light_ClearLights (lightingdata_t *ldata) +{ + ldata->lights.size = 0; + ldata->lightstyles.size = 0; + ldata->lightleafs.size = 0; + ldata->lightvis.size = 0; + if (ldata->sun_pvs) { + set_delete (ldata->sun_pvs); + } + ldata->sun_pvs = 0; + if (ldata->pvs) { + set_delete (ldata->pvs); + } + ldata->pvs = 0; + ldata->leaf = 0; +} + +void +Light_EnableSun (lightingdata_t *ldata) +{ + scene_t *scene = ldata->scene; + model_t *model = scene->worldmodel; + + if (!ldata->sun_pvs) { + ldata->sun_pvs = set_new_size (model->brush.visleafs); + } + set_expand (ldata->sun_pvs, model->brush.visleafs); + set_empty (ldata->sun_pvs); + // Any leaf with sky surfaces can potentially see the sun, thus put + // the sun "in" every leaf with a sky surface + // however, skip leaf 0 as it is the exterior solid leaf + for (unsigned l = 1; l < model->brush.modleafs; l++) { + if (model->brush.leaf_flags[l] & SURF_DRAWSKY) { + set_add (ldata->sun_pvs, l - 1); //pvs is 1-based + } + } + // any leaf visible from a leaf with a sky surface (and thus the sun) + // can receive shadows from the sun + expand_pvs (ldata->sun_pvs, model); +} + +void +Light_FindVisibleLights (lightingdata_t *ldata) +{ + scene_t *scene = ldata->scene; + mleaf_t *leaf = scene->viewleaf; + model_t *model = scene->worldmodel; + + if (!leaf) { + return; + } + if (!ldata->pvs) { + ldata->pvs = set_new_size (model->brush.visleafs); + } + + if (leaf != ldata->leaf) { + //double start = Sys_DoubleTime (); + int flags = 0; + + if (leaf == model->brush.leafs) { + set_everything (ldata->pvs); + } else { + Mod_LeafPVS_set (leaf, model, 0, ldata->pvs); + expand_pvs (ldata->pvs, model); + } + for (unsigned i = 0; i < model->brush.visleafs; i++) { + if (set_is_member (ldata->pvs, i)) { + flags |= model->brush.leaf_flags[i + 1]; + } + } + ldata->leaf = leaf; + + //double end = Sys_DoubleTime (); + //Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); + + int visible = 0; + memset (ldata->lightvis.a, 0, ldata->lightvis.size * sizeof (byte)); + for (size_t i = 0; i < ldata->lightleafs.size; i++) { + int l = ldata->lightleafs.a[i]; + if ((l == -1 && (flags & SURF_DRAWSKY)) + || set_is_member (ldata->pvs, l)) { + ldata->lightvis.a[i] = 1; + visible++; + } + } + //Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible, + // ldata->lightvis.size); + } +} diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index 681ca0771..19aea339d 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -169,8 +169,7 @@ gl_R_NewScene (scene_t *scene) brush->leafs[i].efrags = NULL; // Force a vis update - r_refdef.viewleaf = NULL; - R_MarkLeaves (); + R_MarkLeaves (0); R_ClearParticles (); diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 5ea42af56..7c8d04502 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -199,8 +199,7 @@ glsl_R_NewScene (scene_t *scene) r_refdef.worldmodel = scene->worldmodel; // Force a vis update - r_refdef.viewleaf = NULL; - R_MarkLeaves (); + R_MarkLeaves (0); R_ClearParticles (); glsl_R_RegisterTextures (scene->models, scene->num_models); diff --git a/libs/video/renderer/r_bsp.c b/libs/video/renderer/r_bsp.c index 31951b46f..2976bda16 100644 --- a/libs/video/renderer/r_bsp.c +++ b/libs/video/renderer/r_bsp.c @@ -47,7 +47,7 @@ static mleaf_t *r_oldviewleaf; static set_t *solid; void -R_MarkLeaves (void) +R_MarkLeaves (mleaf_t *viewleaf) { set_t *vis; int c; @@ -56,12 +56,12 @@ R_MarkLeaves (void) msurface_t **mark; mod_brush_t *brush = &r_refdef.worldmodel->brush; - if (r_oldviewleaf == r_refdef.viewleaf && !r_novis) + if (r_oldviewleaf == viewleaf && !r_novis) return; r_visframecount++; - r_oldviewleaf = r_refdef.viewleaf; - if (!r_refdef.viewleaf) + r_oldviewleaf = viewleaf; + if (!viewleaf) return; if (r_novis) { @@ -73,7 +73,7 @@ R_MarkLeaves (void) } vis = solid; } else - vis = Mod_LeafPVS (r_refdef.viewleaf, r_refdef.worldmodel); + vis = Mod_LeafPVS (viewleaf, r_refdef.worldmodel); for (unsigned i = 0; i < brush->visleafs; i++) { if (set_is_member (vis, i)) { diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index a199fa368..365bb9dde 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -270,20 +270,21 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs) R_RunParticles (r_data->frametime); R_AnimateLight (); - refdef->viewleaf = 0; - if (refdef->worldmodel) { + if (scr_scene && scr_scene->worldmodel) { + scr_scene->viewleaf = 0; vec4f_t position = refdef->frame.position; - refdef->viewleaf = Mod_PointInLeaf ((vec_t*)&position, refdef->worldmodel);//FIXME + scr_scene->viewleaf = Mod_PointInLeaf ((vec_t*)&position, + scr_scene->worldmodel);//FIXME r_dowarpold = r_dowarp; if (r_waterwarp) { - r_dowarp = refdef->viewleaf->contents <= CONTENTS_WATER; + r_dowarp = scr_scene->viewleaf->contents <= CONTENTS_WATER; } if (r_dowarp && !warp_buffer) { warp_buffer = r_funcs->create_frame_buffer (r_data->vid->width, r_data->vid->height); } + R_MarkLeaves (scr_scene->viewleaf); } - R_MarkLeaves (); R_PushDlights (vec3_origin); r_funcs->begin_frame (); diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 9bd3c3f1c..03d988965 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -167,8 +167,7 @@ R_NewScene (scene_t *scene) R_InitSky (brush->skytexture); // Force a vis update - r_refdef.viewleaf = NULL; - R_MarkLeaves (); + R_MarkLeaves (0); R_ClearParticles (); diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 7a97377d3..ad8252160 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -50,6 +50,8 @@ #include "QF/sys.h" #include "QF/va.h" +#include "QF/scene/scene.h" + #include "QF/Vulkan/qf_lighting.h" #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/barrier.h" @@ -68,79 +70,16 @@ #include "r_internal.h" #include "vid_vulkan.h" -static vec4f_t ref_direction = { 0, 0, 1, 0 }; - -static void -expand_pvs (set_t *pvs, model_t *model) -{ - set_t base_pvs = SET_STATIC_INIT (model->brush.visleafs, alloca); - set_assign (&base_pvs, pvs); - for (unsigned i = 0; i < model->brush.visleafs; i++) { - if (set_is_member (&base_pvs, i)) { - Mod_LeafPVS_mix (model->brush.leafs + i + 1, model, 0, pvs); - } - } -} - -static void -find_visible_lights (vulkan_ctx_t *ctx) -{ - //qfv_device_t *device = ctx->device; - //qfv_devfuncs_t *dfunc = device->funcs; - lightingctx_t *lctx = ctx->lighting_context; - lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; - - mleaf_t *leaf = r_refdef.viewleaf; - model_t *model = r_refdef.worldmodel; - - if (!leaf || !model) { - return; - } - - if (leaf != lframe->leaf) { - //double start = Sys_DoubleTime (); - int flags = 0; - - if (leaf == model->brush.leafs) { - set_everything (lframe->pvs); - } else { - Mod_LeafPVS_set (leaf, model, 0, lframe->pvs); - expand_pvs (lframe->pvs, model); - } - for (unsigned i = 0; i < model->brush.visleafs; i++) { - if (set_is_member (lframe->pvs, i)) { - flags |= model->brush.leaf_flags[i + 1]; - } - } - lframe->leaf = leaf; - - //double end = Sys_DoubleTime (); - //Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); - - int visible = 0; - memset (lframe->lightvis.a, 0, lframe->lightvis.size * sizeof (byte)); - for (size_t i = 0; i < lctx->lightleafs.size; i++) { - int l = lctx->lightleafs.a[i]; - if ((l == -1 && (flags & SURF_DRAWSKY)) - || set_is_member (lframe->pvs, l)) { - lframe->lightvis.a[i] = 1; - visible++; - } - } - //Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible, - // lframe->lightvis.size); - } -} - static void update_lights (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; lightingctx_t *lctx = ctx->lighting_context; + lightingdata_t *ldata = lctx->ldata; lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; - find_visible_lights (ctx); + Light_FindVisibleLights (ldata); dlight_t *lights[MaxLights]; qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); @@ -168,12 +107,12 @@ update_lights (vulkan_ctx_t *ctx) light_data->lights[i].direction = (vec4f_t) { 0, 0, 1, 1 }; } - for (size_t i = 0; (i < lframe->lightvis.size + for (size_t i = 0; (i < ldata->lightvis.size && light_data->lightCount < MaxLights); i++) { - if (lframe->lightvis.a[i]) { - qfv_light_t *light = &light_data->lights[light_data->lightCount++]; - *light = lctx->lights.a[i]; - light->color[3] *= style_intensities[lctx->lightstyles.a[i]]; + if (ldata->lightvis.a[i]) { + light_t *light = &light_data->lights[light_data->lightCount++]; + *light = ldata->lights.a[i]; + light->color[3] *= style_intensities[ldata->lightstyles.a[i]]; } } @@ -202,10 +141,13 @@ Vulkan_Lighting_Draw (qfv_renderframe_t *rFrame) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; qfv_renderpass_t *renderpass = rFrame->renderpass; + lightingctx_t *lctx = ctx->lighting_context; + if (!lctx->scene) { + return; + } update_lights (ctx); - lightingctx_t *lctx = ctx->lighting_context; __auto_type cframe = &ctx->frames.a[ctx->curFrame]; lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = lframe->cmd; @@ -299,9 +241,6 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t)); ctx->lighting_context = lctx; - DARRAY_INIT (&lctx->lights, 16); - DARRAY_INIT (&lctx->lightstyles, 16); - DARRAY_INIT (&lctx->lightleafs, 16); DARRAY_INIT (&lctx->lightmats, 16); DARRAY_INIT (&lctx->lightlayers, 16); DARRAY_INIT (&lctx->lightimages, 16); @@ -376,10 +315,6 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) shadow_set->a[i], va (ctx->va_ctx, "lighting:shadow_set:%zd", i)); - DARRAY_INIT (&lframe->lightvis, 16); - lframe->pvs = 0; - lframe->leaf = 0; - QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); lframe->cmd = cmdSet->a[0]; @@ -455,13 +390,9 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) for (size_t i = 0; i < lctx->frames.size; i++) { lightingframe_t *lframe = &lctx->frames.a[i]; dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0); - DARRAY_CLEAR (&lframe->lightvis); } dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0); dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); - DARRAY_CLEAR (&lctx->lights); - DARRAY_CLEAR (&lctx->lightstyles); - DARRAY_CLEAR (&lctx->lightleafs); DARRAY_CLEAR (&lctx->lightmats); DARRAY_CLEAR (&lctx->lightimages); DARRAY_CLEAR (&lctx->lightlayers); @@ -469,240 +400,16 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) free (lctx->frames.a); free (lctx); } - -static void -dump_light (qfv_light_t *light, int leaf, mat4f_t mat) -{ - Sys_MaskPrintf (SYS_vulkan, - "[%g, %g, %g] %g, " - "[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n", - VEC4_EXP (light->color), - VEC4_EXP (light->position), - VEC4_EXP (light->direction), - VEC4_EXP (light->attenuation), - leaf); -// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 0)); -// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 1)); -// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 2)); -// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 3)); -} - -static float -parse_float (const char *str, float defval) -{ - float val = defval; - if (str) { - char *end; - val = strtof (str, &end); - if (end == str) { - val = defval; - } - } - return val; -} - -static void -parse_vector (const char *str, vec_t *val) -{ - if (str) { - int num = sscanf (str, "%f %f %f", VectorExpandAddr (val)); - while (num < 3) { - val[num++] = 0; - } - } -} - -static float -ecos (float ang) -{ - if (ang == 90 || ang == -90) { - return 0; - } - if (ang == 180 || ang == -180) { - return -1; - } - if (ang == 0 || ang == 360) { - return 1; - } - return cos (ang * M_PI / 180); -} - -static float -esin (float ang) -{ - if (ang == 90) { - return 1; - } - if (ang == -90) { - return -1; - } - if (ang == 180 || ang == -180) { - return 0; - } - if (ang == 0 || ang == 360) { - return 0; - } - return sin (ang * M_PI / 180); -} - -static vec4f_t -sun_vector (const vec_t *ang) -{ - // ang is yaw, pitch (maybe roll, but ignored - vec4f_t vec = { - ecos (ang[1]) * ecos (ang[0]), - ecos (ang[1]) * esin (ang[0]), - esin (ang[1]), - 0, - }; - return vec; -} - -static void -parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model) -{ - qfv_light_t light = {}; - float sunlight; - //float sunlight2; - vec3_t sunangle = { 0, -90, 0 }; - - set_expand (lctx->sun_pvs, model->brush.visleafs); - set_empty (lctx->sun_pvs); - sunlight = parse_float (PL_String (PL_ObjectForKey (entity, - "_sunlight")), 0); - //sunlight2 = parse_float (PL_String (PL_ObjectForKey (entity, - // "_sunlight2")), 0); - parse_vector (PL_String (PL_ObjectForKey (entity, "_sun_mangle")), - sunangle); - if (sunlight <= 0) { - return; - } - VectorSet (1, 1, 1, light.color); - light.color[3] = sunlight; - light.position = sun_vector (sunangle); - light.direction = light.position; - light.direction[3] = 1; - light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; - DARRAY_APPEND (&lctx->lights, light); - DARRAY_APPEND (&lctx->lightstyles, 0); - DARRAY_APPEND (&lctx->lightleafs, -1); - - // Any leaf with sky surfaces can potentially see the sun, thus put - // the sun "in" every leaf with a sky surface - // however, skip leaf 0 as it is the exterior solid leaf - for (unsigned l = 1; l < model->brush.modleafs; l++) { - if (model->brush.leaf_flags[l] & SURF_DRAWSKY) { - set_add (lctx->sun_pvs, l - 1); //pvs is 1-based - } - } - // any leaf visible from a leaf with a sky surface (and thus the sun) - // can receive shadows from the sun - expand_pvs (lctx->sun_pvs, model); -} - -static vec4f_t -parse_position (const char *str) -{ - vec3_t vec = {}; - sscanf (str, "%f %f %f", VectorExpandAddr (vec)); - return (vec4f_t) {vec[0], vec[1], vec[2], 1}; -} - -static void -parse_light (qfv_light_t *light, int *style, const plitem_t *entity, - const plitem_t *targets) -{ - const char *str; - int model = 0; - - /*Sys_Printf ("{\n"); - for (int i = PL_D_NumKeys (entity); i-- > 0; ) { - const char *field = PL_KeyAtIndex (entity, i); - const char *value = PL_String (PL_ObjectForKey (entity, field)); - Sys_Printf ("\t%s = %s\n", field, value); - } - Sys_Printf ("}\n");*/ - - // omnidirectional light (unit length xyz so not treated as ambient) - light->direction = (vec4f_t) { 0, 0, 1, 1 }; - // bright white - light->color = (vec4f_t) { 1, 1, 1, 300 }; - - if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { - light->position = parse_position (str); - } - - if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { - plitem_t *target = PL_ObjectForKey (targets, str); - vec4f_t dir = { 1, 0, 0, 0 }; - if (target) { - if ((str = PL_String (PL_ObjectForKey (target, "origin")))) { - dir = parse_position (str); - dir = normalf (dir - light->position); - } - } - - float angle = 40; - if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) { - angle = atof (str); - } - dir[3] = -cos (angle * M_PI / 360); // half angle - light->direction = dir; - } - - if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) - || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { - light->color[3] = atof (str); - } - - if ((str = PL_String (PL_ObjectForKey (entity, "style")))) { - *style = atoi (str) & 0x3f; - } - - if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) { - model = atoi (str) & 0x7; - if (model == LM_INVERSE2) { - model = LM_INVERSE3; //FIXME for marcher (need a map) - } - } - - if ((str = PL_String (PL_ObjectForKey (entity, "color"))) - || (str = PL_String (PL_ObjectForKey (entity, "_color")))) { - sscanf (str, "%f %f %f", VectorExpandAddr (light->color)); - VectorScale (light->color, 1/255.0, light->color); - } - - vec4f_t attenuation = { 1, 0, 0, 0 }; // inverse square - switch (model) { - case LM_LINEAR: - attenuation = (vec4f_t) { 0, 0, 1, 1 / fabsf (light->color[3]) }; - break; - case LM_INVERSE: - attenuation = (vec4f_t) { 0, 1.0 / 128, 0, 0 }; - break; - case LM_INVERSE2: - attenuation = (vec4f_t) { 1.0 / 16384, 0, 0, 0 }; - break; - case LM_INFINITE: - attenuation = (vec4f_t) { 0, 0, 1, 0 }; - break; - case LM_AMBIENT: - attenuation = (vec4f_t) { 0, 0, 1, 0 }; - light->direction = (vec4f_t) { 0, 0, 0, 1 }; - break; - case LM_INVERSE3: - attenuation = (vec4f_t) { 1.0 / 16384, 2.0 / 128, 1, 0 }; - break; - } - light->attenuation = attenuation; -} +#if 0 +static vec4f_t ref_direction = { 0, 0, 1, 0 }; static void create_light_matrices (lightingctx_t *lctx) { - DARRAY_RESIZE (&lctx->lightmats, lctx->lights.size); - for (size_t i = 0; i < lctx->lights.size; i++) { - qfv_light_t *light = &lctx->lights.a[i]; + lightingdata_t *ldata = lctx->ldata; + DARRAY_RESIZE (&lctx->lightmats, ldata->lights.size); + for (size_t i = 0; i < ldata->lights.size; i++) { + light_t *light = &ldata->lights.a[i]; mat4f_t view; mat4f_t proj; int mode = ST_NONE; @@ -754,8 +461,8 @@ create_light_matrices (lightingctx_t *lctx) static int light_compare (const void *_l2, const void *_l1) { - const qfv_light_t *l1 = _l1; - const qfv_light_t *l2 = _l2; + const light_t *l1 = _l1; + const light_t *l2 = _l2; if (l1->color[3] == l2->color[3]) { return (l1->position[3] == l2->position[3]) @@ -852,8 +559,9 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) qfv_devfuncs_t *dfunc = device->funcs; qfv_physdev_t *physDev = device->physDev; int maxLayers = physDev->properties.limits.maxImageArrayLayers; - qfv_light_t *lights = lctx->lights.a; - int numLights = lctx->lights.size; + lightingdata_t *ldata = lctx->ldata; + light_t *lights = ldata->lights.a; + int numLights = ldata->lights.size; int size = -1; int numLayers = 0; int totalLayers = 0; @@ -861,7 +569,7 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) size_t memsize = 0; DARRAY_RESIZE (&lctx->lightlayers, numLights); - qsort (lights, numLights, sizeof (qfv_light_t), light_compare); + qsort (lights, numLights, sizeof (light_t), light_compare); for (int i = 0; i < numLights; i++) { int layers = 1; int shadow = ST_NONE; @@ -961,10 +669,10 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) } int mode = ST_NONE; - if (!lctx->lights.a[i].position[3]) { + if (!ldata->lights.a[i].position[3]) { mode = ST_CASCADE; } else { - if (lctx->lights.a[i].direction[3] > -0.5) { + if (ldata->lights.a[i].direction[3] > -0.5) { mode = ST_CUBE; } else { mode = ST_PLANE; @@ -977,117 +685,13 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) Sys_MaskPrintf (SYS_vulkan, "shadow maps: %d layers in %zd images: %zd\n", totalLayers, lctx->lightimages.size, memsize); } - -static void -locate_lights (model_t *model, lightingctx_t *lctx) -{ - qfv_light_t *lights = lctx->lights.a; - DARRAY_RESIZE (&lctx->lightleafs, lctx->lights.size); - for (size_t i = 0; i < lctx->lights.size; i++) { - mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model); - lctx->lightleafs.a[i] = leaf - model->brush.leafs - 1; - } -} +#endif void -Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) +Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx) { lightingctx_t *lctx = ctx->lighting_context; - plitem_t *entities = 0; - if (!entity_data) { - return; - } - - lctx->lights.size = 0; - lctx->lightstyles.size = 0; - lctx->lightleafs.size = 0; - lctx->lightmats.size = 0; - if (lctx->sun_pvs) { - set_delete (lctx->sun_pvs); - } - lctx->sun_pvs = set_new_size (model->brush.visleafs); - for (size_t i = 0; i < ctx->frames.size; i++) { - __auto_type lframe = &lctx->frames.a[i]; - if (lframe->pvs) { - set_delete (lframe->pvs); - } - lframe->pvs = set_new_size (model->brush.visleafs); - } - - clear_shadows (ctx); - - script_t *script = Script_New (); - Script_Start (script, "ent data", entity_data); - - if (Script_GetToken (script, 1)) { - if (strequal (script->token->str, "(")) { - // new style (plist) entity data - entities = PL_GetPropertyList (entity_data, &ctx->hashlinks); - } else { - // old style entity data - Script_UngetToken (script); - // FIXME ED_ConvertToPlist aborts if an error is encountered. - entities = ED_ConvertToPlist (script, 0, &ctx->hashlinks); - } - } - Script_Delete (script); - - if (entities) { - plitem_t *targets = PL_NewDictionary (&ctx->hashlinks); - - // find all the targets so spotlights can be aimed - for (int i = 1; i < PL_A_NumObjects (entities); i++) { - plitem_t *entity = PL_ObjectAtIndex (entities, i); - const char *targetname = PL_String (PL_ObjectForKey (entity, - "targetname")); - if (targetname && !PL_ObjectForKey (targets, targetname)) { - PL_D_AddObject (targets, targetname, entity); - } - } - - for (int i = 0; i < PL_A_NumObjects (entities); i++) { - plitem_t *entity = PL_ObjectAtIndex (entities, i); - const char *classname = PL_String (PL_ObjectForKey (entity, - "classname")); - if (!classname) { - continue; - } - if (strequal (classname, "worldspawn")) { - // parse_sun can add many lights - parse_sun (lctx, entity, model); - } else if (strnequal (classname, "light", 5)) { - qfv_light_t light = {}; - int style = 0; - - parse_light (&light, &style, entity, targets); - // some lights have 0 output, so drop them - if (light.color[3]) { - DARRAY_APPEND (&lctx->lights, light); - DARRAY_APPEND (&lctx->lightstyles, style); - } - } - } - for (size_t i = 0; i < ctx->frames.size; i++) { - lightingframe_t *lframe = &lctx->frames.a[i]; - DARRAY_RESIZE (&lframe->lightvis, lctx->lights.size); - } - // targets does not own the objects, so need to remove them before - // freeing targets - for (int i = PL_D_NumKeys (targets); i-- > 0; ) { - PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i)); - } - PL_Free (targets); - PL_Free (entities); - } - Sys_MaskPrintf (SYS_vulkan, "loaded %zd lights\n", lctx->lights.size); - if (lctx->lights.size) { - build_shadow_maps (lctx, ctx); - create_light_matrices (lctx); - locate_lights (model, lctx); - for (size_t i = 0; i < lctx->lights.size; i++) { - dump_light (&lctx->lights.a[i], lctx->lightleafs.a[i], - lctx->lightmats.a[i]); - } - } + lctx->scene = scene; + lctx->ldata = scene->lights; } diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 17c74ec6b..af5ae3dd1 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -142,14 +142,13 @@ Vulkan_NewScene (scene_t *scene, vulkan_ctx_t *ctx) r_refdef.worldmodel = scene->worldmodel; // Force a vis update - r_refdef.viewleaf = NULL; - R_MarkLeaves (); + R_MarkLeaves (0); R_ClearParticles (); Vulkan_RegisterTextures (scene->models, scene->num_models, ctx); //Vulkan_BuildLightmaps (scene->models, scene->num_models, ctx); Vulkan_BuildDisplayLists (scene->models, scene->num_models, ctx); - Vulkan_LoadLights (scene->worldmodel, scene->worldmodel->brush.entities, ctx); + Vulkan_LoadLights (scene, ctx); } /*void From 4a4e16399a6fbcd05ca0b3dc936a59352d8f5e7e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 15:22:02 +0900 Subject: [PATCH 62/77] [client] Clean up world entity parsing a bit Now the entities are parsed only once and the resulting data reused. --- include/client/world.h | 3 +- libs/client/cl_light.c | 101 +++++++++++++++++------------------------ libs/client/cl_world.c | 11 ++--- 3 files changed, 47 insertions(+), 68 deletions(-) diff --git a/include/client/world.h b/include/client/world.h index e96ec48e3..2e1f79107 100644 --- a/include/client/world.h +++ b/include/client/world.h @@ -66,7 +66,6 @@ void CL_ParseBaseline (struct msg_s *msg, struct entity_state_s *baseline, void CL_ParseStatic (struct msg_s *msg, int version); void CL_MapCfg (const char *mapname); void CL_World_NewMap (const char *mapname, const char *skyname); -void CL_LoadLights (struct model_s *model, const char *entity_data, - struct lightingdata_s *ldata); +void CL_LoadLights (struct plitem_s *entities, struct scene_s *scene); #endif//__client_world_h diff --git a/libs/client/cl_light.c b/libs/client/cl_light.c index 8aa9cb39c..ecb946956 100644 --- a/libs/client/cl_light.c +++ b/libs/client/cl_light.c @@ -9,9 +9,9 @@ #include "QF/model.h" #include "QF/plist.h" #include "QF/progs.h" //for ED_ConvertToPlist -#include "QF/script.h" #include "QF/set.h" #include "QF/scene/light.h" +#include "QF/scene/scene.h" #include "QF/simd/vec4f.h" #include "client/world.h" @@ -238,78 +238,59 @@ locate_lights (model_t *model, lightingdata_t *ldata) } void -CL_LoadLights (model_t *model, const char *entity_data, lightingdata_t *ldata) +CL_LoadLights (plitem_t *entities, scene_t *scene) { - plitem_t *entities = 0; + lightingdata_t *ldata = scene->lights; + model_t *model = scene->worldmodel; - if (!entity_data) { + Light_ClearLights (ldata); + ldata->sun_pvs = set_new_size (model->brush.visleafs); + if (!entities) { return; } - Light_ClearLights (ldata); + plitem_t *targets = PL_NewDictionary (0); - ldata->sun_pvs = set_new_size (model->brush.visleafs); - - script_t *script = Script_New (); - Script_Start (script, "ent data", entity_data); - - if (Script_GetToken (script, 1)) { - if (!strcmp (script->token->str, "(")) { - // new style (plist) entity data - entities = PL_GetPropertyList (entity_data, 0); - } else { - // old style entity data - Script_UngetToken (script); - // FIXME ED_ConvertToPlist aborts if an error is encountered. - entities = ED_ConvertToPlist (script, 0, 0); + // find all the targets so spotlights can be aimed + for (int i = 1; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *targetname = PL_String (PL_ObjectForKey (entity, + "targetname")); + if (targetname && !PL_ObjectForKey (targets, targetname)) { + PL_D_AddObject (targets, targetname, entity); } } - Script_Delete (script); - if (entities) { - plitem_t *targets = PL_NewDictionary (0); + for (int i = 0; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *classname = PL_String (PL_ObjectForKey (entity, + "classname")); + if (!classname) { + continue; + } + if (!strcmp (classname, "worldspawn")) { + // parse_sun can add many lights + parse_sun (ldata, entity); + } else if (!strncmp (classname, "light", 5)) { + light_t light = {}; + int style = 0; - // find all the targets so spotlights can be aimed - for (int i = 1; i < PL_A_NumObjects (entities); i++) { - plitem_t *entity = PL_ObjectAtIndex (entities, i); - const char *targetname = PL_String (PL_ObjectForKey (entity, - "targetname")); - if (targetname && !PL_ObjectForKey (targets, targetname)) { - PL_D_AddObject (targets, targetname, entity); + parse_light (&light, &style, entity, targets); + // some lights have 0 output, so drop them + if (light.color[3]) { + DARRAY_APPEND (&ldata->lights, light); + DARRAY_APPEND (&ldata->lightstyles, style); } } - - for (int i = 0; i < PL_A_NumObjects (entities); i++) { - plitem_t *entity = PL_ObjectAtIndex (entities, i); - const char *classname = PL_String (PL_ObjectForKey (entity, - "classname")); - if (!classname) { - continue; - } - if (!strcmp (classname, "worldspawn")) { - // parse_sun can add many lights - parse_sun (ldata, entity); - } else if (!strncmp (classname, "light", 5)) { - light_t light = {}; - int style = 0; - - parse_light (&light, &style, entity, targets); - // some lights have 0 output, so drop them - if (light.color[3]) { - DARRAY_APPEND (&ldata->lights, light); - DARRAY_APPEND (&ldata->lightstyles, style); - } - } - } - DARRAY_RESIZE (&ldata->lightvis, ldata->lights.size); - // targets does not own the objects, so need to remove them before - // freeing targets - for (int i = PL_D_NumKeys (targets); i-- > 0; ) { - PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i)); - } - PL_Free (targets); - PL_Free (entities); } + DARRAY_RESIZE (&ldata->lightvis, ldata->lights.size); + // targets does not own the objects, so need to remove them before + // freeing targets + for (int i = PL_D_NumKeys (targets); i-- > 0; ) { + PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i)); + } + PL_Free (targets); + if (ldata->lights.size) { locate_lights (model, ldata); for (size_t i = 0; i < ldata->lights.size; i++) { diff --git a/libs/client/cl_world.c b/libs/client/cl_world.c index 1bcb256fa..4d17b0f5c 100644 --- a/libs/client/cl_world.c +++ b/libs/client/cl_world.c @@ -212,12 +212,6 @@ CL_World_NewMap (const char *mapname, const char *skyname) cl_static_entities.size = 0; - const char *entity_data = worldmodel->brush.entities; - CL_LoadLights (worldmodel, entity_data, cl_world.scene->lights); - - cl_world.scene->models = cl_world.models.a; - cl_world.scene->num_models = cl_world.models.size; - SCR_NewScene (cl_world.scene); if (cl_world.models.a[1] && cl_world.models.a[1]->brush.entities) { if (cl_world.edicts) { PL_Free (cl_world.edicts); @@ -229,5 +223,10 @@ CL_World_NewMap (const char *mapname, const char *skyname) Fog_ParseWorldspawn (cl_world.worldspawn); } } + CL_LoadLights (cl_world.edicts, cl_world.scene); + + cl_world.scene->models = cl_world.models.a; + cl_world.scene->num_models = cl_world.models.size; + SCR_NewScene (cl_world.scene); map_cfg (mapname, 1); } From a31ff3153cc5f418cbe555ea0ec71e16d722093a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 15:36:22 +0900 Subject: [PATCH 63/77] [gamecode] Fail gracefully on invalid entity strings Returning null (and printing some error messages) is far friendlier than aborting. --- libs/gamecode/pr_parse.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index e43aef934..f5031173f 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -299,17 +299,22 @@ ED_ConvertToPlist (script_t *script, int nohack, struct hashlink_s **hashlinks) plitem_t *value; char *token; int anglehack; + const char *msg = ""; while (Script_GetToken (script, 1)) { token = script->token->str; - if (!strequal (token, "{")) - Sys_Error ("ED_ConvertToPlist: EOF without closing brace"); + if (!strequal (token, "{")) { + msg = "EOF without closing brace"; + goto parse_error; + } ent = PL_NewDictionary (hashlinks); while (1) { int n; - if (!Script_GetToken (script, 1)) - Sys_Error ("ED_ConvertToPlist: EOF without closing brace"); + if (!Script_GetToken (script, 1)) { + msg = "EOF without closing brace"; + goto parse_error; + } token = script->token->str; if (strequal (token, "}")) break; @@ -327,12 +332,16 @@ ED_ConvertToPlist (script_t *script, int nohack, struct hashlink_s **hashlinks) } else { key = PL_NewString (token); } - if (!Script_TokenAvailable (script, 0)) - Sys_Error ("ED_ConvertToPlist: EOL without value"); + if (!Script_TokenAvailable (script, 0)) { + msg = "EOL without value"; + goto parse_error; + } Script_GetToken (script, 0); token = script->token->str; - if (strequal (token, "}")) - Sys_Error ("ED_ConvertToPlist: closing brace without data"); + if (strequal (token, "}")) { + msg = "closing brace without data"; + goto parse_error; + } if (anglehack) { dsprintf (dstr, "0 %s 0", token); value = PL_NewString (dstr->str); @@ -346,6 +355,11 @@ ED_ConvertToPlist (script_t *script, int nohack, struct hashlink_s **hashlinks) } dstring_delete (dstr); return plist; +parse_error: + Sys_Printf ("%s:%d: %s", script->file, script->line, msg); + dstring_delete (dstr); + PL_Free (plist); + return 0; } From c26c3b27395a46f32079103b18f473ae79aabf05 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 19:50:14 +0900 Subject: [PATCH 64/77] [mdl] Show bytes remaining if not enough for unpack It turns out Abyss of Pandemonium has a truncated mdl file causing buffer overruns. --- tools/misc/mdl.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/misc/mdl.py b/tools/misc/mdl.py index f9b6698c4..924cdb48d 100644 --- a/tools/misc/mdl.py +++ b/tools/misc/mdl.py @@ -29,7 +29,7 @@ for i in range(m[6]): k[2].append (model[:s]) model = model[s:] skins.append (k) -pprint (skins) +#pprint (skins) stverts = [] for i in range(m[9]): @@ -51,7 +51,11 @@ for i in range (m[11]): model = model[4:] if t==0: if m[1] == 6: - x = unpack ("3B B 3B B 16s", model[:24]) + try: + x = unpack ("3B B 3B B 16s", model[:24]) + except: + print(len(model)) + raise f = (t, ((x[:3], x[3]), (x[4:7], x[7]), x[8]), []) model = model[24:] else: From df5b471342dc348651774975eac80ae95947de20 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 19:53:20 +0900 Subject: [PATCH 65/77] [scene] Support ambient lighting in worldspawn Abyss of Pandemonium uses global ambient light a lot, but doesn't specify it in every map (nothing extracting entities and adding a reasonable value can't fix). I imagine some further tweaking will be needed. --- include/QF/scene/light.h | 1 - libs/client/cl_light.c | 21 +++++++++++++++++++-- libs/scene/light.c | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/QF/scene/light.h b/include/QF/scene/light.h index 4c6845c20..88033c253 100644 --- a/include/QF/scene/light.h +++ b/include/QF/scene/light.h @@ -38,7 +38,6 @@ struct mod_brush_s; #define NumStyles 64 -#define NoStyle -1 #define LM_LINEAR 0 // light - dist (or radius + dist if -ve) #define LM_INVERSE 1 // distFactor1 * light / dist diff --git a/libs/client/cl_light.c b/libs/client/cl_light.c index ecb946956..6cfa2a9ca 100644 --- a/libs/client/cl_light.c +++ b/libs/client/cl_light.c @@ -232,8 +232,16 @@ locate_lights (model_t *model, lightingdata_t *ldata) light_t *lights = ldata->lights.a; DARRAY_RESIZE (&ldata->lightleafs, ldata->lights.size); for (size_t i = 0; i < ldata->lights.size; i++) { - mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model); - ldata->lightleafs.a[i] = leaf - model->brush.leafs - 1; + if (1 || lights[i].position[3]) { + mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model); + ldata->lightleafs.a[i] = leaf - model->brush.leafs - 1; + } else { + if (DotProduct (lights[i].direction, lights[i].direction)) { + ldata->lightleafs.a[i] = -1; + } else { + ldata->lightleafs.a[i] = -2; + } + } } } @@ -271,6 +279,15 @@ CL_LoadLights (plitem_t *entities, scene_t *scene) if (!strcmp (classname, "worldspawn")) { // parse_sun can add many lights parse_sun (ldata, entity); + const char *str; + if ((str = PL_String (PL_ObjectForKey (entity, "light_lev")))) { + light_t light = {}; + light.color = (vec4f_t) { 1, 1, 1, atof (str) }; + light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; + light.direction = (vec4f_t) { 0, 0, 0, 1 }; + DARRAY_APPEND (&ldata->lights, light); + DARRAY_APPEND (&ldata->lightstyles, 0); + } } else if (!strncmp (classname, "light", 5)) { light_t light = {}; int style = 0; diff --git a/libs/scene/light.c b/libs/scene/light.c index fc38e71af..7ccc17dda 100644 --- a/libs/scene/light.c +++ b/libs/scene/light.c @@ -128,7 +128,7 @@ Light_FindVisibleLights (lightingdata_t *ldata) memset (ldata->lightvis.a, 0, ldata->lightvis.size * sizeof (byte)); for (size_t i = 0; i < ldata->lightleafs.size; i++) { int l = ldata->lightleafs.a[i]; - if ((l == -1 && (flags & SURF_DRAWSKY)) + if ((l == -2) || (l == -1 && (flags & SURF_DRAWSKY)) || set_is_member (ldata->pvs, l)) { ldata->lightvis.a[i] = 1; visible++; From d60602421b162f2f74ffac5d20ecd9227e89662a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 19:55:35 +0900 Subject: [PATCH 66/77] [vulkan] Ensure dynamic lights are positional I'm not sure what's up with the weird lighting that results from dynamic lights being directional (sunlight works nicely in marcher, but it has a unit vector for position). --- libs/video/renderer/vulkan/vulkan_lighting.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index ad8252160..f31322159 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -102,10 +102,12 @@ update_lights (vulkan_ctx_t *ctx) // dynamic lights seem a tad faint, so 16x map lights light_data->lights[i].color[3] = lights[i]->radius / 16; VectorCopy (lights[i]->origin, light_data->lights[i].position); + // dlights are local point sources + light_data->lights[i].position[3] = 1; light_data->lights[i].attenuation = (vec4f_t) { 0, 0, 1, 1/lights[i]->radius }; - light_data->lights[i].direction = - (vec4f_t) { 0, 0, 1, 1 }; + // full sphere, normal light (not ambient) + light_data->lights[i].direction = (vec4f_t) { 0, 0, 1, 1 }; } for (size_t i = 0; (i < ldata->lightvis.size && light_data->lightCount < MaxLights); i++) { From b2928b5ed7707fa1d2de1bdfd60c904b41f689d6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 19:58:37 +0900 Subject: [PATCH 67/77] [client] Reverse the direction of sunlight Maps specify sunlight as shining in a specific direction, but the lighting system wants the direction to the sun as it's used directly in shading calculations. Direction correctness confirmed by disabling other lights and checking marcher's outside scene (ensuring the flat ground was lit). As a bonus, I've finally confirmed I actually have the skybox in the correct orientation (sunlight vector more or less matched the position of the sun in marcher's sky). --- libs/client/cl_light.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/client/cl_light.c b/libs/client/cl_light.c index 6cfa2a9ca..e06e921f5 100644 --- a/libs/client/cl_light.c +++ b/libs/client/cl_light.c @@ -120,7 +120,7 @@ parse_sun (lightingdata_t *ldata, plitem_t *entity) } VectorSet (1, 1, 1, light.color); light.color[3] = sunlight; - light.position = sun_vector (sunangle); + light.position = -sun_vector (sunangle); light.direction = light.position; light.direction[3] = 1; light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; From 41a12f066b540e372ef69968e7d91831290cd89b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 20:36:25 +0900 Subject: [PATCH 68/77] [client] Clean up light loading By adding Light_AddLight to scene light management --- include/QF/scene/light.h | 1 + libs/client/cl_light.c | 37 +++++-------------------------------- libs/scene/light.c | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/include/QF/scene/light.h b/include/QF/scene/light.h index 88033c253..542431bf3 100644 --- a/include/QF/scene/light.h +++ b/include/QF/scene/light.h @@ -73,6 +73,7 @@ typedef struct lightingdata_s { lightingdata_t *Light_CreateLightingData (struct scene_s *scene); void Light_DestroyLightingData (lightingdata_t *ldata); void Light_ClearLights (lightingdata_t *ldata); +void Light_AddLight (lightingdata_t *ldata, const light_t *light, int style); void Light_EnableSun (lightingdata_t *ldata); void Light_FindVisibleLights (lightingdata_t *ldata); diff --git a/libs/client/cl_light.c b/libs/client/cl_light.c index e06e921f5..5af325739 100644 --- a/libs/client/cl_light.c +++ b/libs/client/cl_light.c @@ -124,9 +124,7 @@ parse_sun (lightingdata_t *ldata, plitem_t *entity) light.direction = light.position; light.direction[3] = 1; light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; - DARRAY_APPEND (&ldata->lights, light); - DARRAY_APPEND (&ldata->lightstyles, 0); - DARRAY_APPEND (&ldata->lightleafs, -1); + Light_AddLight (ldata, &light, 0); } static vec4f_t @@ -226,25 +224,6 @@ parse_light (light_t *light, int *style, const plitem_t *entity, light->attenuation = attenuation; } -static void -locate_lights (model_t *model, lightingdata_t *ldata) -{ - light_t *lights = ldata->lights.a; - DARRAY_RESIZE (&ldata->lightleafs, ldata->lights.size); - for (size_t i = 0; i < ldata->lights.size; i++) { - if (1 || lights[i].position[3]) { - mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model); - ldata->lightleafs.a[i] = leaf - model->brush.leafs - 1; - } else { - if (DotProduct (lights[i].direction, lights[i].direction)) { - ldata->lightleafs.a[i] = -1; - } else { - ldata->lightleafs.a[i] = -2; - } - } - } -} - void CL_LoadLights (plitem_t *entities, scene_t *scene) { @@ -285,8 +264,7 @@ CL_LoadLights (plitem_t *entities, scene_t *scene) light.color = (vec4f_t) { 1, 1, 1, atof (str) }; light.attenuation = (vec4f_t) { 0, 0, 1, 0 }; light.direction = (vec4f_t) { 0, 0, 0, 1 }; - DARRAY_APPEND (&ldata->lights, light); - DARRAY_APPEND (&ldata->lightstyles, 0); + Light_AddLight (ldata, &light, 0); } } else if (!strncmp (classname, "light", 5)) { light_t light = {}; @@ -295,12 +273,10 @@ CL_LoadLights (plitem_t *entities, scene_t *scene) parse_light (&light, &style, entity, targets); // some lights have 0 output, so drop them if (light.color[3]) { - DARRAY_APPEND (&ldata->lights, light); - DARRAY_APPEND (&ldata->lightstyles, style); + Light_AddLight (ldata, &light, style); } } } - DARRAY_RESIZE (&ldata->lightvis, ldata->lights.size); // targets does not own the objects, so need to remove them before // freeing targets for (int i = PL_D_NumKeys (targets); i-- > 0; ) { @@ -308,11 +284,8 @@ CL_LoadLights (plitem_t *entities, scene_t *scene) } PL_Free (targets); - if (ldata->lights.size) { - locate_lights (model, ldata); - for (size_t i = 0; i < ldata->lights.size; i++) { - dump_light (&ldata->lights.a[i], ldata->lightleafs.a[i]); - } + for (size_t i = 0; i < ldata->lights.size; i++) { + dump_light (&ldata->lights.a[i], ldata->lightleafs.a[i]); } Sys_MaskPrintf (SYS_lighting, "loaded %zd lights\n", ldata->lights.size); } diff --git a/libs/scene/light.c b/libs/scene/light.c index 7ccc17dda..3b1d1bd3c 100644 --- a/libs/scene/light.c +++ b/libs/scene/light.c @@ -66,6 +66,28 @@ Light_ClearLights (lightingdata_t *ldata) ldata->leaf = 0; } +void +Light_AddLight (lightingdata_t *ldata, const light_t *light, int style) +{ + scene_t *scene = ldata->scene; + model_t *model = scene->worldmodel; + + DARRAY_APPEND (&ldata->lights, *light); + DARRAY_APPEND (&ldata->lightstyles, style); + + int visleaf = -1; // directional light + if (light->position[3]) { + // positional light + mleaf_t *leaf = Mod_PointInLeaf (&light->position[0], model); + visleaf = leaf - model->brush.leafs - 1; + } else if (!DotProduct (light->direction, light->direction)) { + // ambient light + visleaf = -2; + } + DARRAY_APPEND (&ldata->lightleafs, visleaf); + DARRAY_APPEND (&ldata->lightvis, 0); +} + void Light_EnableSun (lightingdata_t *ldata) { From 2818fc12a531e1ab2bfba96b534b1970239caae7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 21:22:44 +0900 Subject: [PATCH 69/77] [model] Initialize r_notexture_mip in the right places That being in the renderer. This is why qwaq needed that call to Mod_ProcessTexture (but no longer does :) --- libs/models/brush/gl_model_brush.c | 3 --- libs/models/brush/glsl_model_brush.c | 3 --- libs/models/brush/vulkan_model_brush.c | 3 --- libs/video/renderer/gl/gl_rmisc.c | 4 ++++ libs/video/renderer/glsl/glsl_bsp.c | 3 +++ libs/video/renderer/vulkan/vulkan_bsp.c | 4 ++++ 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 4e81f35f1..02ed475a1 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -52,8 +52,6 @@ #include "mod_internal.h" #include "r_internal.h" -static gltex_t gl_notexture = { }; - static tex_t * Mod_LoadAnExternalTexture (const char *tname, const char *mname) { @@ -122,7 +120,6 @@ gl_Mod_ProcessTexture (model_t *mod, texture_t *tx) const char *name; if (!tx) { - r_notexture_mip->render = &gl_notexture; return; } if (gl_textures_external) { diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index 541982f74..da6fad3d0 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -60,8 +60,6 @@ #include "mod_internal.h" #include "r_internal.h" -static glsltex_t glsl_notexture = { }; - static void glsl_brush_clear (model_t *m, void *data) { @@ -105,7 +103,6 @@ void glsl_Mod_ProcessTexture (model_t *mod, texture_t *tx) { if (!tx) { - r_notexture_mip->render = &glsl_notexture; return; } glsltex_t *tex = tx->render; diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index b1933de59..f706083a2 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -62,8 +62,6 @@ #include "r_internal.h" #include "vid_vulkan.h" -static vulktex_t vulkan_notexture = { }; - static void vulkan_brush_clear (model_t *mod, void *data) { @@ -302,7 +300,6 @@ Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, vulkan_ctx_t *ctx) mod->clear = vulkan_brush_clear; mod->data = mctx; - r_notexture_mip->render = &vulkan_notexture; if (mod->brush.numtextures) { load_textures (mod, ctx); } diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index 19aea339d..026e0eb77 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -73,6 +73,8 @@ #include "varrays.h" #include "vid_gl.h" +static gltex_t gl_notexture = { }; + static void gl_R_LoadSky_f (void) { @@ -115,6 +117,8 @@ gl_R_TimeRefresh_f (void) void gl_R_Init (void) { + r_notexture_mip->render = &gl_notexture; + R_Init_Cvars (); Cmd_AddCommand ("timerefresh", gl_R_TimeRefresh_f, diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index a4bd95182..76dca2469 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -103,6 +103,7 @@ static double sky_time; static quat_t default_color = { 1, 1, 1, 1 }; static quat_t last_color; +static glsltex_t glsl_notexture = { }; static const char *bsp_vert_effects[] = { @@ -1282,6 +1283,8 @@ glsl_R_InitBsp (void) int vert; int frag; + r_notexture_mip->render = &glsl_notexture; + vert_shader = GLSL_BuildShader (bsp_vert_effects); frag_shader = GLSL_BuildShader (bsp_lit_effects); vert = GLSL_CompileShader ("quakebsp.vert", vert_shader, diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index b202fd988..b1e1bda28 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -98,6 +98,8 @@ static float identity[] = { 0, 0, 0, 1, }; +static vulktex_t vulkan_notexture = { }; + #define ALLOC_CHUNK 64 typedef struct bsppoly_s { @@ -1342,6 +1344,8 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; + r_notexture_mip->render = &vulkan_notexture; + qfvPushDebug (ctx, "bsp init"); bspctx_t *bctx = calloc (1, sizeof (bspctx_t)); From 7b275ebab6726e1c4b07afd5c4272b1bcae1bc32 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 21:24:22 +0900 Subject: [PATCH 70/77] [vulkan] Don't update lights that don't exist However, the lighting pass still needs to be run in order to generate the solid color image. --- libs/video/renderer/vulkan/vulkan_lighting.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index f31322159..ce61d83c2 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -148,7 +148,9 @@ Vulkan_Lighting_Draw (qfv_renderframe_t *rFrame) if (!lctx->scene) { return; } - update_lights (ctx); + if (lctx->scene->lights) { + update_lights (ctx); + } __auto_type cframe = &ctx->frames.a[ctx->curFrame]; lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; From d850285e3fe04320fe84f772a60a07d454eb644c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 21:26:18 +0900 Subject: [PATCH 71/77] [ruamoko] Allow scenes to be fetched by C code Need to clean up that part of the API, though. --- include/rua_internal.h | 1 + libs/ruamoko/rua_scene.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/rua_internal.h b/include/rua_internal.h index 80f97003a..85880d715 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -65,5 +65,6 @@ void RUA_Mersenne_Init (struct progs_s *pr, int secure); void RUA_Model_Init (struct progs_s *pr, int secure); struct model_s *Model_GetModel (progs_t *pr, int handle); void RUA_Scene_Init (struct progs_s *pr, int secure); +struct scene_s *Scene_GetScene (struct progs_s *pr, pr_ulong_t handle); #endif//__rua_internal_h diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index 1c577d6fd..57e4543ee 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -180,6 +180,17 @@ bi_Scene_DeleteScene (progs_t *pr, void *_res) rua_delete_scene (res, scene); } +scene_t * +Scene_GetScene (progs_t *pr, pr_ulong_t handle) +{ + if (!handle) { + return 0; + } + rua_scene_resources_t *res = PR_Resources_Find (pr, "Scene"); + rua_scene_t *scene = rua_scene_get (res, P_ULONG (pr, 0)); + return scene->scene; +} + static void bi_Scene_CreateEntity (progs_t *pr, void *_res) { @@ -221,10 +232,13 @@ bi_Entity_SetModel (progs_t *pr, void *_res) pr_int_t model_id = P_INT (pr, 1); entity_t *ent = rua_entity_get (res, ent_id); model_t *model = Model_GetModel (pr, model_id); + pr_ulong_t scene_id = ent_id & 0xffffffff; + // bad scene caught above + rua_scene_t *scene = rua_scene_get (res, scene_id); R_RemoveEfrags (ent); ent->renderer.model = model; - R_AddEfrags (&r_data->refdef->worldmodel->brush, ent);//FIXME r_data + R_AddEfrags (&scene->scene->worldmodel->brush, ent); } static void @@ -502,6 +516,6 @@ RUA_Scene_Init (progs_t *pr, int secure) res->pr = pr; - PR_Resources_Register (pr, "scene", res, bi_scene_clear); + PR_Resources_Register (pr, "Scene", res, bi_scene_clear); PR_RegisterBuiltins (pr, builtins, res); } From 95264b3a54322cc433cb8b8dc2e249981fad8a51 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 21:30:14 +0900 Subject: [PATCH 72/77] [ruamoko] Move emtpy_world into scene And use it as the default worldmodel for new scenes. Since it's statically allocated, it shouldn't cause any harm so long as no one tries to free it. --- libs/scene/scene.c | 37 +++++++++++++++++++++ ruamoko/qwaq/builtins/graphics.c | 56 ++++++-------------------------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/libs/scene/scene.c b/libs/scene/scene.c index 13742f2a9..e9620abee 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -38,6 +38,7 @@ #include "QF/mathlib.h" #include "QF/progs.h" // for PR_RESMAP #include "QF/sys.h" +#include "QF/model.h" #include "QF/scene/entity.h" #include "QF/scene/scene.h" @@ -45,6 +46,40 @@ #include "scn_internal.h" +static mleaf_t empty_leafs[] = { + [1] = { + .contents = CONTENTS_EMPTY, + .mins = {-INFINITY, -INFINITY, -INFINITY}, + .maxs = { INFINITY, INFINITY, INFINITY}, + }, +}; + +static mnode_t *empty_leaf_parents[] = { + [1] = 0, +}; + +static int empty_leaf_flags[] = { + [1] = 0, +}; + +static char empty_entities[] = { 0 }; + +static model_t empty_world = { + .type = mod_brush, + .radius = INFINITY, + .mins = {-INFINITY, -INFINITY, -INFINITY}, + .maxs = { INFINITY, INFINITY, INFINITY}, + .brush = { + .modleafs = 2, + .visleafs = 1, + .nodes = (mnode_t *) &empty_leafs[1], + .leafs = empty_leafs, + .entities = empty_entities, + .leaf_parents = empty_leaf_parents, + .leaf_flags = empty_leaf_flags, + }, +}; + scene_t * Scene_NewScene (void) { @@ -55,6 +90,8 @@ Scene_NewScene (void) res = calloc (1, sizeof (scene_resources_t)); *(scene_resources_t **)&scene->resources = res; + scene->worldmodel = &empty_world; + return scene; } diff --git a/ruamoko/qwaq/builtins/graphics.c b/ruamoko/qwaq/builtins/graphics.c index 6b1737906..c3a088b99 100644 --- a/ruamoko/qwaq/builtins/graphics.c +++ b/ruamoko/qwaq/builtins/graphics.c @@ -41,26 +41,20 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$"; #include #include "QF/cbuf.h" -#include "QF/cdaudio.h" -#include "QF/console.h" #include "QF/draw.h" -#include "QF/dstring.h" #include "QF/input.h" -#include "QF/model.h" -#include "QF/plugin.h" #include "QF/progs.h" #include "QF/quakefs.h" #include "QF/render.h" #include "QF/ruamoko.h" #include "QF/screen.h" #include "QF/sound.h" -#include "QF/sys.h" -#include "QF/vid.h" #include "QF/input/event.h" #include "QF/plugin/console.h" -#include "QF/plugin/vid_render.h" + +#include "rua_internal.h" #include "ruamoko/qwaq/qwaq.h" @@ -86,40 +80,6 @@ static progs_t *bi_rprogs; static pr_func_t qc2d; static int event_handler_id; -static mleaf_t empty_leafs[] = { - [1] = { - .contents = CONTENTS_EMPTY, - .mins = {-INFINITY, -INFINITY, -INFINITY}, - .maxs = { INFINITY, INFINITY, INFINITY}, - }, -}; - -static mnode_t *empty_leaf_parents[] = { - [1] = 0, -}; - -static int empty_leaf_flags[] = { - [1] = 0, -}; - -static char empty_entities[] = { 0 }; - -static model_t empty_world = { - .type = mod_brush, - .radius = INFINITY, - .mins = {-INFINITY, -INFINITY, -INFINITY}, - .maxs = { INFINITY, INFINITY, INFINITY}, - .brush = { - .modleafs = 2, - .visleafs = 1, - .nodes = (mnode_t *) &empty_leafs[1], - .leafs = empty_leafs, - .entities = empty_entities, - .leaf_parents = empty_leaf_parents, - .leaf_flags = empty_leaf_flags, - }, -}; - static void bi_2d (void) { @@ -133,6 +93,13 @@ static SCR_Func bi_2dfuncs[] = { 0, }; +static void +bi_newscene (progs_t *pr, void *_res) +{ + pr_ulong_t scene_id = P_ULONG (pr, 0); + SCR_NewScene (Scene_GetScene (pr, scene_id)); +} + static void bi_refresh (progs_t *pr, void *_res) { @@ -162,6 +129,7 @@ bi_shutdown (progs_t *pr, void *_res) #define bi(x,n,np,params...) {#x, bi_##x, n, np, {params}} #define p(type) PR_PARAM(type) static builtin_t builtins[] = { + bi(newscene, -1, 1, p(long)), bi(refresh, -1, 0), bi(refresh_2d, -1, 1, p(func)), bi(shutdown, -1, 0), @@ -230,8 +198,4 @@ BI_Graphics_Init (progs_t *pr) //CDAudio_Init (); Con_NewMap (); basetime = Sys_DoubleTime (); - if (mod_funcs->Mod_ProcessTexture) { - mod_funcs->Mod_ProcessTexture (&empty_world, 0); - } - //r_funcs->R_NewMap (&empty_world, 0, 0); } From d14b17567e910e32ac0ab23fe997b83860282ddc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 23:43:39 +0900 Subject: [PATCH 73/77] [ruamoko] Add builtins for adding lights to scenes Pretty much just raw wrappers around the C versions. I'm not sure about Light_EnableSun (even in C), but it does build the sky surf pvs. --- libs/ruamoko/rua_scene.c | 147 ++++++++++++++++++++++++++++++++++++++- ruamoko/include/scene.h | 15 ++++ ruamoko/lib/scene.r | 7 ++ 3 files changed, 166 insertions(+), 3 deletions(-) diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index 57e4543ee..71af32449 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -45,6 +45,7 @@ #include "QF/plugin/vid_render.h" #include "QF/scene/entity.h" +#include "QF/scene/light.h" #include "QF/scene/scene.h" #include "QF/scene/transform.h" @@ -56,10 +57,18 @@ typedef struct rua_scene_s { scene_t *scene; } rua_scene_t; +typedef struct rua_lighting_s { + struct rua_lighting_s *next; + struct rua_lighting_s **prev; + lightingdata_t *ldata; +} rua_lighting_t; + typedef struct rua_scene_resources_s { progs_t *pr; PR_RESMAP (rua_scene_t) scene_map; + PR_RESMAP (rua_lighting_t) lighting_map; rua_scene_t *scenes; + rua_lighting_t *ldatas; } rua_scene_resources_t; static rua_scene_t * @@ -96,6 +105,12 @@ rua__scene_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) } #define rua_scene_get(res, id) rua__scene_get(res, id, __FUNCTION__) +static int __attribute__((pure)) +rua_scene_index (rua_scene_resources_t *res, rua_scene_t *scene) +{ + return PR_RESINDEX (res->scene_map, scene); +} + static entity_t * __attribute__((pure)) rua__entity_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) { @@ -134,10 +149,44 @@ rua__transform_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) } #define rua_transform_get(res, id) rua__transform_get(res, id, __FUNCTION__) -static int __attribute__((pure)) -rua_scene_index (rua_scene_resources_t *res, rua_scene_t *scene) +static rua_lighting_t * +rua_lighting_new (rua_scene_resources_t *res) { - return PR_RESINDEX (res->scene_map, scene); + return PR_RESNEW (res->lighting_map); +} + +static void +rua_lighting_free (rua_scene_resources_t *res, rua_lighting_t *ldata) +{ + if (ldata->next) { + ldata->next->prev = ldata->prev; + } + *ldata->prev = ldata->next; + ldata->prev = 0; + PR_RESFREE (res->lighting_map, ldata); +} + +static rua_lighting_t * __attribute__((pure)) +rua__lighting_get (rua_scene_resources_t *res, pr_ulong_t id, const char *name) +{ + rua_lighting_t *ldata = 0; + + if (id <= 0xffffffffu) { + ldata = PR_RESGET (res->lighting_map, (pr_int_t) id); + } + + // ldata->prev will be null if the handle is unallocated + if (!ldata || !ldata->prev) { + PR_RunError (res->pr, "invalid lighting passed to %s", name + 3); + } + return ldata; +} +#define rua_lighting_get(res, id) rua__lighting_get(res, id, __FUNCTION__) + +static int __attribute__((pure)) +rua_lighting_index (rua_scene_resources_t *res, rua_lighting_t *ldata) +{ + return PR_RESINDEX (res->lighting_map, ldata); } #define MAKE_ID(id, sc_id) ((((pr_ulong_t) (id)) << 32) \ @@ -213,6 +262,22 @@ bi_Scene_DestroyEntity (progs_t *pr, void *_res) Scene_DestroyEntity (scene->scene, ent); } +static void +bi_Scene_SetLighting (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + pr_ulong_t scene_id = P_ULONG (pr, 0); + rua_scene_t *scene = rua_scene_get (res, scene_id); + pr_ulong_t ldata_id = P_ULONG (pr, 1); + rua_lighting_t *ldata = 0; + + if (ldata_id) { + ldata = rua_lighting_get (res, ldata_id); + } + + scene->scene->lights = ldata->ldata; +} + static void bi_Entity_GetTransform (progs_t *pr, void *_res) { @@ -453,6 +518,74 @@ bi_Transform_Up (progs_t *pr, void *_res) R_PACKED (pr, pr_vec4_t) = Transform_Up (transform); } +static void +bi_Light_CreateLightingData (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + pr_ulong_t scene_id = P_ULONG (pr, 0); + rua_scene_t *scene = rua_scene_get (res, scene_id); + + rua_lighting_t *ldata = rua_lighting_new (res); + + ldata->ldata = Light_CreateLightingData (scene->scene); + + ldata->next = res->ldatas; + if (res->ldatas) { + res->ldatas->prev = &ldata->next; + } + ldata->prev = &res->ldatas; + res->ldatas = ldata; + + // ldata id in lower 32-bits for all handles + // upper 32-bits reserved + R_ULONG (pr) = MAKE_ID (0, rua_lighting_index (res, ldata)); +} + +static void +rua_delete_lighting (rua_scene_resources_t *res, rua_lighting_t *ldata) +{ + Light_DestroyLightingData (ldata->ldata); + rua_lighting_free (res, ldata); +} + +static void +bi_Light_DestroyLightingData (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + rua_lighting_t *ldata = rua_lighting_get (res, P_ULONG (pr, 0)); + + rua_delete_lighting (res, ldata); +} + +static void +bi_Light_ClearLights (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + rua_lighting_t *ldata = rua_lighting_get (res, P_ULONG (pr, 0)); + + Light_ClearLights (ldata->ldata); +} + +static void +bi_Light_AddLight (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + rua_lighting_t *ldata = rua_lighting_get (res, P_ULONG (pr, 0)); + light_t *light = &P_PACKED (pr, light_t, 1); + int style = P_INT (pr, 5); + + Light_AddLight (ldata->ldata, light, style); +} + +static void +bi_Light_EnableSun (progs_t *pr, void *_res) +{ + rua_scene_resources_t *res = _res; + rua_lighting_t *ldata = rua_lighting_get (res, P_ULONG (pr, 0)); + + Light_EnableSun (ldata->ldata); +} + #define p(type) PR_PARAM(type) #define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), } #define bi(x,np,params...) {#x, bi_##x, -1, np, {params}} @@ -461,6 +594,7 @@ static builtin_t builtins[] = { bi(Scene_DeleteScene, 1, p(ulong)), bi(Scene_CreateEntity, 1, p(ulong)), bi(Scene_DestroyEntity, 1, p(ulong)), + bi(Scene_SetLighting , 2, p(ulong), p(ulong)), bi(Entity_GetTransform, 1, p(ulong)), bi(Entity_SetModel, 2, p(ulong), p(int)), @@ -496,6 +630,13 @@ static builtin_t builtins[] = { bi(Transform_Right, 1, p(ulong)), bi(Transform_Up, 1, p(ulong)), + bi(Light_CreateLightingData, 1, p(ulong)), + bi(Light_DestroyLightingData, 1, p(ulong)), + bi(Light_ClearLights, 1, p(ulong)), + bi(Light_AddLight, 5, p(ulong),// really, 3 + p(vec4), p(vec4), p(vec4), p(vec4), p(int)), + bi(Light_EnableSun, 1, p(ulong)), + {0} }; diff --git a/ruamoko/include/scene.h b/ruamoko/include/scene.h index cf66b5d82..fabbc1c2f 100644 --- a/ruamoko/include/scene.h +++ b/ruamoko/include/scene.h @@ -6,16 +6,25 @@ typedef struct { vec4 col[4]; } mat4x4; +typedef struct light_s { + vec4 color; + vec4 position; + vec4 direction; + vec4 attenuation; +} light_t; + //FIXME need a handle type typedef struct { long handle; } scene_t; typedef struct { long handle; } entity_t; typedef struct { long handle; } transform_t; +typedef struct { long handle; } lightingdata_t; typedef struct { int handle; } model_t; scene_t Scene_NewScene (void); void Scene_DeleteScene (scene_t scene); entity_t Scene_CreateEntity (scene_t scene); void Scene_DestroyEntity (entity_t ent); +void Scene_SetLighting (scene_t scene, lightingdata_t ldata); transform_t Entity_GetTransform (entity_t ent); void Entity_SetModel (entity_t ent, model_t model); @@ -48,6 +57,12 @@ vec4 Transform_Forward (transform_t transform); vec4 Transform_Right (transform_t transform); vec4 Transform_Up (transform_t transform); +lightingdata_t Light_CreateLightingData (scene_t scene); +void Light_DestroyLightingData (lightingdata_t ldata); +void Light_ClearLights (lightingdata_t ldata); +void Light_AddLight (lightingdata_t ldata, light_t light); +void Light_EnableSun (lightingdata_t ldata); + model_t Model_Load (string path); void Model_Unload (model_t model); diff --git a/ruamoko/lib/scene.r b/ruamoko/lib/scene.r index 6bcf931ed..fd40f2321 100644 --- a/ruamoko/lib/scene.r +++ b/ruamoko/lib/scene.r @@ -4,6 +4,7 @@ scene_t Scene_NewScene (void) = #0; void Scene_DeleteScene (scene_t scene) = #0; entity_t Scene_CreateEntity (scene_t scene) = #0; void Scene_DestroyEntity (entity_t ent) = #0; +void Scene_SetLighting (scene_t scene, lightingdata_t ldata) = #0; transform_t Entity_GetTransform (entity_t ent) = #0; void Entity_SetModel (entity_t ent, model_t model) = #0; @@ -36,5 +37,11 @@ vec4 Transform_Forward (transform_t transform) = #0; vec4 Transform_Right (transform_t transform) = #0; vec4 Transform_Up (transform_t transform) = #0; +lightingdata_t Light_CreateLightingData (scene_t scene) = #0; +void Light_DestroyLightingData (lightingdata_t ldata) = #0; +void Light_ClearLights (lightingdata_t ldata) = #0; +void Light_AddLight (lightingdata_t ldata, light_t light) = #0; +void Light_EnableSun (lightingdata_t ldata) = #0; + model_t Model_Load (string path) = #0; void Model_Unload (model_t model) = #0; From 72cb7d3fdd773cd39fc3d4b1445a2b486ea42db3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 23:45:21 +0900 Subject: [PATCH 74/77] [scene] Make the empty world work with lights Needed visibility and a sky surf flag, otherwise no lights were visible (why does this seem familiar?). --- libs/scene/scene.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/scene/scene.c b/libs/scene/scene.c index e9620abee..e2a49a61e 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -46,11 +46,14 @@ #include "scn_internal.h" +static byte empty_visdata[] = { 0x01 }; + static mleaf_t empty_leafs[] = { [1] = { .contents = CONTENTS_EMPTY, .mins = {-INFINITY, -INFINITY, -INFINITY}, .maxs = { INFINITY, INFINITY, INFINITY}, + .compressed_vis = empty_visdata, }, }; @@ -59,7 +62,7 @@ static mnode_t *empty_leaf_parents[] = { }; static int empty_leaf_flags[] = { - [1] = 0, + [1] = SURF_DRAWSKY, }; static char empty_entities[] = { 0 }; @@ -75,6 +78,7 @@ static model_t empty_world = { .nodes = (mnode_t *) &empty_leafs[1], .leafs = empty_leafs, .entities = empty_entities, + .visdata = empty_visdata, .leaf_parents = empty_leaf_parents, .leaf_flags = empty_leaf_flags, }, From 4abcaff9803096236554ec9368aeadce6915ba6e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2022 23:46:24 +0900 Subject: [PATCH 75/77] [vulkan] Normalize the normal vectors on alias models I was wondering why scaled-down quake-guy was dimmer than full-size quake-guy. And the per-fragment normalization gives the illusion of smoothness if you don't look at his legs (and even then...). --- libs/video/renderer/vulkan/shader/alias.vert | 2 +- libs/video/renderer/vulkan/shader/alias_gbuf.frag | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/shader/alias.vert b/libs/video/renderer/vulkan/shader/alias.vert index 52f390781..7292bee8e 100644 --- a/libs/video/renderer/vulkan/shader/alias.vert +++ b/libs/video/renderer/vulkan/shader/alias.vert @@ -34,6 +34,6 @@ main (void) pos = (Model * vertex); gl_Position = Projection3d * (View * pos); position = pos; - normal = mat3 (Model) * norm; + normal = normalize (mat3 (Model) * norm); st = uv; } diff --git a/libs/video/renderer/vulkan/shader/alias_gbuf.frag b/libs/video/renderer/vulkan/shader/alias_gbuf.frag index 2b751a0c7..50bc8f4b7 100644 --- a/libs/video/renderer/vulkan/shader/alias_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/alias_gbuf.frag @@ -33,6 +33,6 @@ main (void) frag_color = c; frag_emission = e; - frag_normal = vec4(normal, 1); + frag_normal = vec4(normalize(normal), 1); frag_position = position; } From ed82b5f299d2ad6a8d413f240737a13c81269233 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 May 2022 08:26:55 +0900 Subject: [PATCH 76/77] [ruamoko] Clean up lighting data blocks Don't want to leak memory. --- libs/ruamoko/rua_scene.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index 71af32449..c5daeb45f 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -645,6 +645,9 @@ bi_scene_clear (progs_t *pr, void *_res) { rua_scene_resources_t *res = _res; + while (res->ldatas) { + rua_delete_lighting (res, res->ldatas); + } while (res->scenes) { rua_delete_scene (res, res->scenes); } From 551c6b82cb1ec0159a9c10da187692059eff6481 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 May 2022 08:32:19 +0900 Subject: [PATCH 77/77] [vulkan] Tweak spotlight cone edges a little --- libs/video/renderer/vulkan/shader/lighting.frag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index a9e5cb7d2..41ee21629 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -50,7 +50,7 @@ spot_cone (LightData light, vec3 incoming) vec3 dir = light.direction.xyz; float cone = light.direction.w; float spotdot = dot (incoming, dir); - return 1 - smoothstep (cone, cone + 0.02, spotdot); + return 1 - smoothstep (cone, .995 * cone + 0.005, spotdot); } float