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/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/Makemodule.am b/include/QF/Makemodule.am index b18a43f55..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 @@ -178,7 +179,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/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/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/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 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/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index d146b298c..3524b27ee 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -1,7 +1,13 @@ #ifndef __QF_Vulkan_image_h #define __QF_Vulkan_image_h +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + #include "QF/darray.h" +#include "QF/image.h" typedef struct qfv_imageset_s DARRAY_TYPE (VkImage) qfv_imageset_t; @@ -95,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/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/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/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index ec4de2c3f..ef6a6bb24 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -33,53 +33,26 @@ #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 { - vec3_t color; - int data; - vec3_t position; - float light; - vec3_t direction; - float cone; -} 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 StyleMask 0x07f -#define ModelMask 0x380 -#define ShadowMask 0xc00 - -#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 NumStyles 64 +#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) typedef struct qfv_light_buffer_s { - float intensity[NumStyles + 4]; - float distFactor1; - float distFactor2; + light_t lights[MaxLights] __attribute__((aligned(16))); int lightCount; - qfv_light_t lights[MaxLights] __attribute__((aligned(16))); - mat4f_t shadowMat[MaxLights]; - vec4f_t shadowCascade[MaxLights]; + //mat4f_t shadowMat[MaxLights]; + //vec4f_t shadowCascade[MaxLights]; } qfv_light_buffer_t; #define LIGHTING_BUFFER_INFOS 1 @@ -101,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 @@ -118,13 +86,13 @@ typedef struct lightingctx_s { VkSampler sampler; VkDeviceMemory light_memory; VkDeviceMemory shadow_memory; - qfv_lightset_t lights; - 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; @@ -133,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/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/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index f729c2b65..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 @@ -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/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/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/include/QF/input.h b/include/QF/input.h index 6b4167aca..a701cdd68 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 int 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/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/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 diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 6f775de78..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; @@ -58,9 +59,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); @@ -107,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/progs/pr_comp.h b/include/QF/progs/pr_comp.h index cef8c3ef6..696de6218 100644 --- a/include/QF/progs/pr_comp.h +++ b/include/QF/progs/pr_comp.h @@ -433,7 +433,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/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..542431bf3 --- /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 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_AddLight (lightingdata_t *ldata, const light_t *light, int style); +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 b74c29955..ec95221a2 100644 --- a/include/QF/scene/scene.h +++ b/include/QF/scene/scene.h @@ -43,6 +43,11 @@ 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; + struct mleaf_s *viewleaf; + struct lightingdata_s *lights; } 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/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 }; 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/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/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/include/client/world.h b/include/client/world.h index 191e313d8..2e1f79107 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; @@ -51,6 +50,7 @@ extern worldscene_t cl_world; struct msg_s; struct entity_state_s; +struct lightingdata_s; void CL_World_Init (void); @@ -66,5 +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 plitem_s *entities, struct scene_s *scene); #endif//__client_world_h 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/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/include/r_internal.h b/include/r_internal.h index 8b43dac0a..95a1c26bc 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); @@ -73,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/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/include/rua_internal.h b/include/rua_internal.h index b58eb4530..85880d715 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -62,6 +62,9 @@ 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); +struct scene_s *Scene_GetScene (struct progs_s *pr, pr_ulong_t handle); #endif//__rua_internal_h diff --git a/include/snd_internal.h b/include/snd_internal.h index 63dd6a62d..e9558e95e 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. */ diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 9cfe51ca7..df1e4b6bd 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -67,15 +67,13 @@ 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; 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 @@ -95,8 +93,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; //FIXME not sure I like it being here (also, type name) qfv_output_t output; 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..5af325739 --- /dev/null +++ b/libs/client/cl_light.c @@ -0,0 +1,291 @@ +#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/set.h" +#include "QF/scene/light.h" +#include "QF/scene/scene.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 }; + Light_AddLight (ldata, &light, 0); +} + +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; +} + +void +CL_LoadLights (plitem_t *entities, scene_t *scene) +{ + lightingdata_t *ldata = scene->lights; + model_t *model = scene->worldmodel; + + Light_ClearLights (ldata); + ldata->sun_pvs = set_new_size (model->brush.visleafs); + if (!entities) { + return; + } + + 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); + 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 }; + Light_AddLight (ldata, &light, 0); + } + } 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]) { + Light_AddLight (ldata, &light, style); + } + } + } + // 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); + + 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_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..4d17b0f5c 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 @@ -119,7 +121,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 +207,11 @@ 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); + if (cl_world.models.a[1] && cl_world.models.a[1]->brush.entities) { if (cl_world.edicts) { PL_Free (cl_world.edicts); @@ -219,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); } 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; } 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); diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index 85d91c3b2..5abc7e4d5 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -52,55 +52,67 @@ #include "compat.h" -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 +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 (int i = 0; i < num_skins; i++) { + __auto_type skin = alias_ctx->skins.a + i; + 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); + } } void diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index c48500ad7..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,28 +91,34 @@ glsl_alias_clear (model_t *m, void *data) } } -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) +{ + 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, + skin->skin_num, skin->group_num, skin->skindesc); + } } void 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..797ec38de 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -48,20 +48,22 @@ // a pose is a single set of vertexes. a frame may be // an animating sequence of poses - -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) { - byte *pskin; + 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); - pskin = Hunk_AllocName (0, skinsize, alias_ctx->mod->name); - skindesc->skin = (byte *) pskin - (byte *) alias_ctx->header; + for (size_t i = 0; i < alias_ctx->skins.size; i++) { + __auto_type skin = alias_ctx->skins.a + i; + byte *texels = texel_block + i * skinsize; - memcpy (pskin, skin, skinsize); - - return skin + skinsize; + skin->skindesc->skin = texels - (byte *) header; + memcpy (texels, skin->texels, skinsize); + } } static void 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/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 2fcc9f5bd..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,8 +300,9 @@ 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; - load_textures (mod, ctx); + if (mod->brush.numtextures) { + load_textures (mod, ctx); + } return; } 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/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) { 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; 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..4f8d5b8c0 --- /dev/null +++ b/libs/ruamoko/rua_model.c @@ -0,0 +1,182 @@ +/* + 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) +{ + if (!handle) { + return 0; + } + 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); +} diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index d43a4da7b..c5daeb45f 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -38,9 +38,14 @@ #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/light.h" #include "QF/scene/scene.h" #include "QF/scene/transform.h" @@ -52,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 * @@ -92,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) { @@ -130,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) \ @@ -176,6 +229,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) { @@ -198,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) { @@ -209,6 +289,23 @@ 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); + 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 (&scene->scene->worldmodel->brush, ent); +} + static void bi_Transform_ChildCount (progs_t *pr, void *_res) { @@ -421,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}} @@ -429,8 +594,10 @@ 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)), bi(Transform_ChildCount, 1, p(ulong)), bi(Transform_GetChild, 2, p(ulong), p(int)), @@ -463,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} }; @@ -471,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); } @@ -483,6 +660,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); } 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/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 }; diff --git a/libs/scene/light.c b/libs/scene/light.c new file mode 100644 index 000000000..3b1d1bd3c --- /dev/null +++ b/libs/scene/light.c @@ -0,0 +1,162 @@ +#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_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) +{ + 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 == -2) || (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/scene/scene.c b/libs/scene/scene.c index e08fb718c..e2a49a61e 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -35,8 +35,10 @@ # include #endif +#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" @@ -44,6 +46,44 @@ #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, + }, +}; + +static mnode_t *empty_leaf_parents[] = { + [1] = 0, +}; + +static int empty_leaf_flags[] = { + [1] = SURF_DRAWSKY, +}; + +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, + .visdata = empty_visdata, + .leaf_parents = empty_leaf_parents, + .leaf_flags = empty_leaf_flags, + }, +}; + scene_t * Scene_NewScene (void) { @@ -54,6 +94,8 @@ Scene_NewScene (void) res = calloc (1, sizeof (scene_resources_t)); *(scene_resources_t **)&scene->resources = res; + scene->worldmodel = &empty_world; + return scene; } @@ -84,6 +126,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; } diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index bc48a77e2..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 $@ @@ -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 \ @@ -218,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 \ @@ -299,8 +301,14 @@ 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 +fstriangle_c = $(vkshaderpath)/fstriangle.vert.spvc pushcolor_src = $(vkshaderpath)/pushcolor.frag pushcolor_c = $(vkshaderpath)/pushcolor.frag.spvc shadow_src = $(vkshaderpath)/shadow.geom @@ -356,8 +364,14 @@ $(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) + $(pushcolor_c): $(pushcolor_src) $(shadow_c): $(shadow_src) @@ -390,7 +404,10 @@ vkshader_c = \ $(aliasf_c) \ $(alias_gbuf_c) \ $(alias_shadow_c) \ + $(iqmv_c) \ + $(iqmf_c) \ $(passthrough_c) \ + $(fstriangle_c) \ $(pushcolor_c) \ $(shadow_c) @@ -443,6 +460,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/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/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index f7056bcfb..026e0eb77 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -66,12 +66,15 @@ #include "QF/GL/qf_vid.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "mod_internal.h" #include "r_internal.h" #include "varrays.h" #include "vid_gl.h" +static gltex_t gl_notexture = { }; + static void gl_R_LoadSky_f (void) { @@ -114,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, @@ -152,7 +157,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,20 +165,19 @@ 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++) brush->leafs[i].efrags = NULL; // Force a vis update - r_refdef.viewleaf = NULL; - R_MarkLeaves (); + R_MarkLeaves (0); R_ClearParticles (); - GL_BuildLightmaps (models, num_models); + GL_BuildLightmaps (scene->models, scene->num_models); // identify sky texture gl_R_ClearTextures (); @@ -189,13 +193,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/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..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[] = { @@ -831,8 +832,6 @@ R_VisitWorldNodes (glslbspctx_t *bctx) } break; } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); } static void @@ -1284,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/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index a2fa1f8f6..7c8d04502 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" @@ -142,7 +143,9 @@ glsl_R_RenderView (void) R_SetupView (); glsl_R_DrawWorld (); glsl_R_DrawSky (); - R_DrawViewModel (); + if (vr_data.view_model) { + R_DrawViewModel (); + } } static void @@ -186,23 +189,22 @@ 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_MarkLeaves (0); 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_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_light.c b/libs/video/renderer/r_light.c index 0c9a50a28..654748dfb 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); diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 6152efce9..365bb9dde 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,40 +72,41 @@ 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] = { - { 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} @@ -268,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 (); @@ -505,3 +508,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_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/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 9f9b852a3..03d988965 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; @@ -165,8 +167,7 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) R_InitSky (brush->skytexture); // Force a vis update - r_refdef.viewleaf = NULL; - R_MarkLeaves (); + R_MarkLeaves (0); R_ClearParticles (); @@ -589,7 +590,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/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index f6a980710..9d99ca43d 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, @@ -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 b60624ae6..132e1f062 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, @@ -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 fdde33ec8..a7d69ada7 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, @@ -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 e23fa7244..a52e3b7eb 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" @@ -63,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" @@ -80,7 +82,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); @@ -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 @@ -541,13 +542,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 @@ -564,6 +562,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 @@ -639,7 +638,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, @@ -729,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, @@ -773,8 +772,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 a7c190fe9..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 @@ -99,22 +98,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 +250,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; } 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/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index c5ce13c0f..f846b1799 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -1,223 +1,101 @@ { + 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; - 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; + @inherit = $properties.flat_color_image_template; + format = r16g16b16a16_sfloat; }; 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 = { + 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 = { @@ -238,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; }, ); 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/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; + }, + ); + }; +} diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 092af713a..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 @@ -266,3 +265,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; +} 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/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/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 40a28a89a..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; @@ -559,17 +557,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 +1002,7 @@ { stage = vertex; name = main; - module = $builtin/passthrough.vert; + module = $builtin/fstriangle.vert; }, { stage = fragment; @@ -1022,13 +1016,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 +1035,7 @@ { stage = vertex; name = main; - module = $builtin/passthrough.vert; + module = $builtin/fstriangle.vert; }, { stage = fragment; @@ -1049,13 +1043,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/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 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); +} diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index a71c83300..0f7e19a7b 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -93,8 +93,14 @@ 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" +static #include "libs/video/renderer/vulkan/shader/pushcolor.frag.spvc" static #include "libs/video/renderer/vulkan/shader/shadow.geom.spvc" @@ -133,7 +139,10 @@ 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) }, { "shadow.geom", shadow_geom, sizeof (shadow_geom) }, {} 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; } 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/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/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 2d384e622..41ee21629 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, .995 * cone + 0.005, 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/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index 390f5dd3c..9f48594b2 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/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/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index cae788c22..077b19cfb 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 1faf34bf5..98effde21 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) 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 e9ad1abd9..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 { @@ -413,6 +415,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). @@ -746,8 +752,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 @@ -853,8 +857,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); @@ -1039,6 +1043,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]; @@ -1091,6 +1098,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; @@ -1334,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)); diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c index 161012ae0..6d8ad105e 100644 --- a/libs/video/renderer/vulkan/vulkan_compose.c +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -102,12 +102,10 @@ 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); - 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_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index f2d1678a7..46604ae24 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; } @@ -840,8 +845,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_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); +} diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 83a8ee061..ce61d83c2 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,96 +70,26 @@ #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); 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 +99,22 @@ 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; + // 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 }; + // full sphere, normal light (not ambient) + 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]) { - light_data->lights[light_data->lightCount++] = lctx->lights.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]]; } } @@ -205,10 +143,15 @@ 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; - - update_lights (ctx); - lightingctx_t *lctx = ctx->lighting_context; + + if (!lctx->scene) { + return; + } + if (lctx->scene->lights) { + update_lights (ctx); + } + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = lframe->cmd; @@ -257,12 +200,10 @@ 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); - 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); @@ -304,8 +245,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->lightleafs, 16); DARRAY_INIT (&lctx->lightmats, 16); DARRAY_INIT (&lctx->lightlayers, 16); DARRAY_INIT (&lctx->lightimages, 16); @@ -380,10 +319,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]; @@ -459,12 +394,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->lightleafs); DARRAY_CLEAR (&lctx->lightmats); DARRAY_CLEAR (&lctx->lightimages); DARRAY_CLEAR (&lctx->lightlayers); @@ -472,219 +404,30 @@ 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] %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, - 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 void -sun_vector (const vec_t *ang, vec_t *vec) -{ - // 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]); -} - -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.data = LM_INFINITE | ST_CASCADE; - light.light = sunlight; - sun_vector (sunangle, light.direction); - light.cone = 1; - DARRAY_APPEND (&lctx->lights, light); - 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 void -parse_light (qfv_light_t *light, 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");*/ - - light->cone = 1; - light->data = 0; - light->light = 300; - VectorSet (1, 1, 1, light->color); - - if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { - sscanf (str, "%f %f %f", VectorExpandAddr (light->position)); - } - - if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { - vec3_t position = {}; - plitem_t *target = PL_ObjectForKey (targets, str); - if (target) { - if ((str = PL_String (PL_ObjectForKey (target, "origin")))) { - sscanf (str, "%f %f %f", VectorExpandAddr (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 - } - - if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) - || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { - light->light = atof (str); - } - - if ((str = PL_String (PL_ObjectForKey (entity, "style")))) { - light->data = atoi (str) & 0x3f; - } - - if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) { - model = (atoi (str) & 0x7) << 7; - if (model == LM_INVERSE2) { - model = LM_INVERSE3; //FIXME for marcher (need a map) - } - light->data |= model; - } - - 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); - } - - 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; - } - } -} +#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; - 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: @@ -693,13 +436,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; @@ -711,7 +455,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); @@ -721,13 +465,14 @@ 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->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 @@ -760,7 +505,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; @@ -769,7 +514,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: @@ -818,8 +563,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; @@ -827,10 +573,20 @@ 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 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 @@ -840,13 +596,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; @@ -861,8 +618,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; @@ -904,115 +671,31 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) lctx->lightviews.a[i] = 0; continue; } + int mode = ST_NONE; + + if (!ldata->lights.a[i].position[3]) { + mode = ST_CASCADE; + } else { + if (ldata->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); } - -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; - lctx->lights.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 = {}; - - parse_light (&light, entity, targets); - // some lights have 0 output, so drop them - if (light.light) { - DARRAY_APPEND (&lctx->lights, light); - } - } - } - 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); - 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 4bb82ecbc..af5ae3dd1 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" @@ -122,14 +123,15 @@ 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); } 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; @@ -137,17 +139,16 @@ 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_MarkLeaves (0); 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, ctx); } /*void 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 4e9c5991a..6eccebcd7 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -455,6 +455,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++) { @@ -469,43 +474,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 @@ -565,9 +533,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 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) * * -------------------------------------------------------------------------- diff --git a/libs/video/targets/vid_win_vulkan.c b/libs/video/targets/vid_win_vulkan.c index f9adb967d..2a8618073 100644 --- a/libs/video/targets/vid_win_vulkan.c +++ b/libs/video/targets/vid_win_vulkan.c @@ -163,10 +163,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) { diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index 43af1897e..c8aa494ea 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -202,10 +202,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) { 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 06ebcb1e1..0d3f0864f 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -227,6 +227,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 @@ -290,7 +295,7 @@ CL_ClearState (void) CL_ClearTEnts (); - r_funcs->R_ClearState (); + SCR_NewScene (0); CL_ClearEnts (); @@ -349,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; } @@ -462,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 c309861fb..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" @@ -630,12 +631,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; } /* @@ -702,19 +697,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 (); @@ -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); @@ -758,19 +759,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); } /* @@ -802,12 +794,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; @@ -830,18 +823,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++; @@ -853,7 +847,8 @@ Host_Frame (float time) { double time1, time2; static double timetotal; - int c, m; + int c; + double m; static int timecount; if (!serverprofile) { @@ -880,7 +875,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); } 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/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 bd717a1c2..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" @@ -292,123 +294,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 +452,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 +703,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 +788,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 +803,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 +827,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 @@ -1048,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/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/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/include/scene.h b/ruamoko/include/scene.h new file mode 100644 index 000000000..fabbc1c2f --- /dev/null +++ b/ruamoko/include/scene.h @@ -0,0 +1,69 @@ +#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; + +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); + +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); + +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); + +#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/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; diff --git a/ruamoko/lib/scene.r b/ruamoko/lib/scene.r new file mode 100644 index 000000000..fd40f2321 --- /dev/null +++ b/ruamoko/lib/scene.r @@ -0,0 +1,47 @@ +#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; +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; + +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; + +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; 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) diff --git a/ruamoko/qwaq/builtins/graphics.c b/ruamoko/qwaq/builtins/graphics.c index 1d6841998..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" @@ -99,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) { @@ -128,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), 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): 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: 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)); } } }