[vulkan] Make a lot of progress for brush models

Light maps are maybe updating, but as nothing is actually rendered yet,
it's hard to tell.
This commit is contained in:
Bill Currie 2021-01-20 01:25:54 +09:00
parent 0622a24380
commit d33f5b8d0d
18 changed files with 2329 additions and 22 deletions

134
include/QF/Vulkan/qf_bsp.h Normal file
View file

@ -0,0 +1,134 @@
/*
qf_bsp.h
Vulkan specific brush model stuff
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2012/1/7
Date: 2021/1/18
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_bsp_h
#define __QF_Vulkan_qf_bsp_h
#include "QF/darray.h"
#include "QF/model.h"
#include "QF/Vulkan/qf_vid.h"
typedef struct bspvert_s {
quat_t vertex;
quat_t tlst;
} bspvert_t;
typedef struct elements_s {
struct elements_s *_next;
struct elements_s *next;
byte *base;
struct dstring_s *list;
} elements_t;
typedef struct elechain_s {
struct elechain_s *_next;
struct elechain_s *next;
int index;
elements_t *elements;
vec_t *transform;
float *color;
} elechain_t;
typedef struct bspframe_s {
uint32_t *indeces;
VkCommandBuffer bsp_cmd;
VkCommandBuffer turb_cmd;
VkCommandBuffer sky_cmd;
VkDescriptorSet descriptors;
} bspframe_t;
typedef struct bspframeset_s
DARRAY_TYPE (bspframe_t) bspframeset_t;
typedef struct texchainset_s
DARRAY_TYPE (struct vulktex_s *) texchainset_t;
typedef struct bspctx_s {
instsurf_t *waterchain;
instsurf_t **waterchain_tail;
instsurf_t *sky_chain;
instsurf_t **sky_chain_tail;
texchainset_t texture_chains;
// for world and non-instance models
instsurf_t *static_instsurfs;
instsurf_t **static_instsurfs_tail;
instsurf_t *free_static_instsurfs;
// for instance models
elechain_t *elechains;
elechain_t **elechains_tail;
elechain_t *free_elechains;
elements_t *elementss;
elements_t **elementss_tail;
elements_t *free_elementss;
instsurf_t *instsurfs;
instsurf_t **instsurfs_tail;
instsurf_t *free_instsurfs;
struct qfv_tex_s *skybox_tex;
quat_t sky_rotation[2];
quat_t sky_velocity;
quat_t sky_fix;
double sky_time;
quat_t default_color;
quat_t last_color;
struct scrap_s *light_scrap;
struct qfv_stagebuf_s *light_stage;
VkDeviceMemory texture_memory;
VkPipeline main;
VkPipelineLayout layout;
size_t vertex_buffer_size;
size_t index_buffer_size;
VkBuffer vertex_buffer;
VkDeviceMemory vertex_memory;
VkBuffer index_buffer;
VkDeviceMemory index_memory;
bspframeset_t frames;
} bspctx_t;
struct vulkan_ctx_s;
void Vulkan_ClearElements (struct vulkan_ctx_s *ctx);
void Vulkan_DrawWorld (struct vulkan_ctx_s *ctx);
void Vulkan_DrawSky (struct vulkan_ctx_s *ctx);
void Vulkan_RegisterTextures (model_t **models, int num_models,
struct vulkan_ctx_s *ctx);
void Vulkan_BuildDisplayLists (model_t **models, int num_models,
struct vulkan_ctx_s *ctx);
void Vulkan_Bsp_Init (struct vulkan_ctx_s *ctx);
void Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx);
void Vulkan_DrawWaterSurfaces (struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_bsp_h

View file

@ -0,0 +1,48 @@
/*
qf_lightmap.h
Vulkan lightmap stuff from the renderer.
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
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_lightmap_h
#define __QF_Vulkan_qf_lightmap_h
#define MAX_LIGHTMAPS 1024
#define BLOCK_WIDTH 64
#define BLOCK_HEIGHT 64
#include "QF/Vulkan/qf_vid.h"
struct vulkan_ctx_s;
struct model_s;
struct msurface_s;
void Vulkan_lightmap_init (struct vulkan_ctx_s *ctx);
void Vulkan_BuildLightmaps (struct model_s **models, int num_models, struct vulkan_ctx_s *ctx);
void Vulkan_CalcLightmaps (struct vulkan_ctx_s *ctx);
void Vulkan_BuildLightMap (struct msurface_s *surf, struct vulkan_ctx_s *ctx);
VkImageView Vulkan_LightmapImageView (struct vulkan_ctx_s *ctx) __attribute__((pure));
void Vulkan_FlushLightmaps (struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_lightmap_h

View file

@ -0,0 +1,37 @@
/*
qf_main.h
Vulkan main stuff from the renderer.
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
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_main_h
#define __QF_Vulkan_qf_main_h
struct vulkan_ctx_s;
void Vulkan_NewMap (model_t *worldmodel, struct model_s **models,
int num_models, struct vulkan_ctx_s *ctx);
void Vulkan_RenderView (struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_main_h

View file

@ -0,0 +1,44 @@
/*
qf_model.h
Vulkan specific model stuff
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2012/1/7
Date: 2021/1/19
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_model_h
#define __QF_Vulkan_qf_model_h
#include "QF/darray.h"
#include "QF/model.h"
#include "QF/Vulkan/qf_vid.h"
typedef struct modelctx_s {
struct vulkan_ctx_s *ctx;
VkDeviceMemory texture_memory;
} modelctx_t;
#endif//__QF_Vulkan_qf_model_h

View file

@ -5,8 +5,12 @@
typedef struct scrap_s scrap_t;
struct qfv_stagebuf_s;
struct qfv_device_s;
scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size,
QFFormat format);
size_t QFV_ScrapSize (scrap_t *scrap);
void QFV_ScrapClear (scrap_t *scrap);
void QFV_DestroyScrap (scrap_t *scrap);
VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure));

View file

@ -180,6 +180,7 @@ void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);
void R_StepActiveU (edge_t *pedge);
void R_RemoveEdges (edge_t *pedge);
void R_AddTexture (texture_t *tex);
struct vulkan_ctx_s;
void R_ClearTextures (void);
void R_InitSurfaceChains (model_t *model);
@ -313,6 +314,7 @@ void R_MarkLights (const vec3_t lightorigin, struct dlight_s *light, int bit,
model_t *model);
void R_LoadSkys (const char *);
//void Vulkan_R_LoadSkys (const char *, struct vulkan_ctx_s *ctx);
void R_LowFPPrecision (void);
void R_HighFPPrecision (void);

View file

@ -63,6 +63,7 @@ typedef struct vulkan_ctx_s {
struct hashtab_s *descriptorPools;
struct hashtab_s *samplers;
struct bspctx_s *bsp_context;
struct drawctx_s *draw_context;
VkCommandPool cmdpool;

View file

@ -217,11 +217,57 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx)
void
Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx)
{
mod_lightmap_bytes = 1;
mod_lightmap_bytes = 3;
if (!bsp->lightdatasize) {
loadmodel->lightdata = NULL;
return;
}
loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname);
memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize);
byte d;
byte *in, *out, *data;
size_t i;
int ver;
QFile *lit_file;
loadmodel->lightdata = 0;
if (mod_lightmap_bytes > 1) {
// LordHavoc: check for a .lit file to load
dstring_t *litfilename = dstring_new ();
dstring_copystr (litfilename, loadmodel->name);
QFS_StripExtension (litfilename->str, litfilename->str);
dstring_appendstr (litfilename, ".lit");
lit_file = QFS_VOpenFile (litfilename->str, 0, loadmodel->vpath);
data = (byte *) QFS_LoadHunkFile (lit_file);
if (data) {
if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I'
&& data[3] == 'T') {
ver = LittleLong (((int32_t *) data)[1]);
if (ver == 1) {
Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str);
loadmodel->lightdata = data + 8;
} else {
Sys_MaskPrintf (SYS_DEV,
"Unknown .lit file version (%d)\n", ver);
}
} else {
Sys_MaskPrintf (SYS_DEV, "Corrupt .lit file (old version?)\n");
}
}
dstring_delete (litfilename);
}
if (loadmodel->lightdata || !bsp->lightdatasize) {
return;
}
// LordHavoc: oh well, expand the white lighting data
loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize * 3,
loadmodel->name);
in = bsp->lightdata;
out = loadmodel->lightdata;
for (i = 0; i < bsp->lightdatasize ; i++) {
d = *in++;
*out++ = d;
*out++ = d;
*out++ = d;
}
}

View file

@ -236,7 +236,10 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \
libs/video/renderer/vulkan/util.c \
libs/video/renderer/vulkan/util.h \
libs/video/renderer/vulkan/vkparse.c \
libs/video/renderer/vulkan/vulkan_bsp.c \
libs/video/renderer/vulkan/vulkan_draw.c \
libs/video/renderer/vulkan/vulkan_lightmap.c \
libs/video/renderer/vulkan/vulkan_main.c \
libs/video/renderer/vulkan/vulkan_matrices.c \
libs/video/renderer/vulkan/vulkan_particles.c \
libs/video/renderer/vulkan/vulkan_texture.c \

View file

@ -39,7 +39,10 @@
#include "QF/plugin/general.h"
#include "QF/plugin/vid_render.h"
#include "QF/Vulkan/qf_bsp.h"
#include "QF/Vulkan/qf_draw.h"
#include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_main.h"
#include "QF/Vulkan/qf_particles.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/command.h"
@ -92,6 +95,7 @@ vulkan_R_Init (void)
// FIXME this should be staged so screen updates can begin while pipelines
// are being built
vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline");
Vulkan_Bsp_Init (vulkan_ctx);
Vulkan_Draw_Init (vulkan_ctx);
Vulkan_Particles_Init (vulkan_ctx);
@ -116,12 +120,6 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
VkDevice dev = device->dev;
qfv_queue_t *queue = &vulkan_ctx->device->queue;
scr_3dfunc ();
while (*scr_funcs) {
(*scr_funcs) ();
scr_funcs++;
}
__auto_type framebuffer
= &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame];
@ -145,6 +143,12 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
attachments,
sc->extent, 1);
scr_3dfunc ();
while (*scr_funcs) {
(*scr_funcs) ();
scr_funcs++;
}
Vulkan_FlushText (vulkan_ctx);
VkCommandBufferBeginInfo beginInfo
@ -168,6 +172,8 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
dfunc->vkCmdExecuteCommands (framebuffer->cmdBuffer,
framebuffer->subCommand->size,
framebuffer->subCommand->a);
// reset for next time around
framebuffer->subCommand->size = 0;
dfunc->vkCmdEndRenderPass (framebuffer->cmdBuffer);
dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer);
@ -208,6 +214,9 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs)
static void
vulkan_R_ClearState (void)
{
R_ClearEfrags ();
R_ClearDlights ();
Vulkan_ClearParticles (vulkan_ctx);
}
static void
@ -218,6 +227,7 @@ vulkan_R_LoadSkys (const char *skyname)
static void
vulkan_R_NewMap (model_t *worldmodel, model_t **models, int num_models)
{
Vulkan_NewMap (worldmodel, models, num_models, vulkan_ctx);
}
static void
@ -228,6 +238,7 @@ vulkan_R_LineGraph (int x, int y, int *h_vals, int count)
static void
vulkan_R_RenderView (void)
{
Vulkan_RenderView (vulkan_ctx);
}
static void
@ -359,13 +370,13 @@ vulkan_R_ViewChanged (float aspect)
static void
vulkan_R_ClearParticles (void)
{
Vulkan_R_ClearParticles (vulkan_ctx);
Vulkan_ClearParticles (vulkan_ctx);
}
static void
vulkan_R_InitParticles (void)
{
Vulkan_R_InitParticles (vulkan_ctx);
Vulkan_InitParticles (vulkan_ctx);
}
static void
@ -593,6 +604,7 @@ vulkan_vid_render_shutdown (void)
df->vkDestroyFence (dev, vulkan_ctx->fence, 0);
df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0);
Vulkan_Draw_Shutdown (vulkan_ctx);
Vulkan_Bsp_Shutdown (vulkan_ctx);
Vulkan_Shutdown_Common (vulkan_ctx);
}

View file

@ -9,6 +9,8 @@
pushcolor = $builtin/pushcolor.frag;
twodv = $builtin/twod.vert;
twodf = $builtin/twod.frag;
quakebspv = $builtin/quakebsp.vert;
quakebspf = $builtin/quakebsp.frag;
};
samplers = {
quakepic = {
@ -44,6 +46,20 @@
},
);
};
quakebsp = {
flags = 0;
maxSets = $framebuffers.size;
bindings = (
{
type = uniform_buffer;
descriptorCount = $framebuffers.size;
},
{
type = combined_image_sampler;
descriptorCount = "5z * $framebuffers.size";
},
);
};
};
setLayouts = {
twod = {
@ -62,6 +78,46 @@
},
);
};
quakebsp = {
bindings = (
{
binding = 0;
descriptorType = uniform_buffer;
descriptorCount = 1;
stageFlags = vertex;
},
{
binding = 1;
descriptorType = combined_image_sampler;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 2;
descriptorType = combined_image_sampler;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 3;
descriptorType = combined_image_sampler;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 4;
descriptorType = combined_image_sampler;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 5;
descriptorType = combined_image_sampler;
descriptorCount = 1;
stageFlags = fragment;
},
);
};
something = {
flags = 0;
bindings = (
@ -84,6 +140,21 @@
twod = {
setLayouts = (twod);
};
quakebsp = {
setLayouts = (quakebsp);
pushConstantRanges = (
{
stageFlags = vertex;
offset = 0;
size = "16 * 4";
},
{
stageFlags = fragment;
offset = 0;
size = 32;
},
);
};
something = {
setLayouts = (something);
pushConstantRanges = (
@ -96,6 +167,95 @@
};
};
pipelines = {
quakebsp.main = {
stages = (
{ stage = vertex; name = main; module = quakebspv; },
{ stage = fragment; name = main; module = quakebspf; },
);
vertexInput = {
bindings = (
{
binding = 0;
stride = "3 * 4 * 4";
inputRate = vertex;
},
);
attributes = (
{
location = 0;
binding = 0;
format = r32g32b32a32_sfloat;
offset = 0;
},
{
location = 1;
binding = 0;
format = r32g32b32a32_sfloat;
offset = 8;
},
);
};
inputAssembly = {
topology = triangle_fan;
primitiveRestartEnable = true;
};
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; };
},
);
};
rasterization = {
depthClampEnable = false;
rasterizerDiscardEnable = false;
polygonMode = fill;
cullMode = back;
frontFace = clockwise;
depthBiasEnable = false;
lineWidth = 1;
};
multisample = {
rasterizationSamples = $msaaSamples;
sampleShadingEnable = false;
minSampleShading = 0.5f;
alphaToCoverageEnable = false;
alphaToOneEnable = false;
};
depthStencil = {
depthTestEnable = true;
depthWriteEnable = true;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
colorBlend = {
logicOpEnable = false;
attachments = ({
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;
});
};
dynamic = {
dynamicState = ( viewport, scissor, blend_constants );
};
layout = quakebsp;
//renderPass = renderpass;
};
twod = {
stages = (
{ stage = vertex; name = main; module = twodv; },

View file

@ -3,8 +3,8 @@
layout (set = 0, binding = 1) uniform sampler2D Texture;
layout (set = 0, binding = 2) uniform sampler2D Glowmap;
layout (set = 0, binding = 3) uniform sampler2D Lightmap;
layout (set = 0, binding = 4) uniform samplerCube SkyCube;
layout (set = 0, binding = 5) uniform sampler2DArray SkySheet;
layout (set = 0, binding = 4) uniform sampler2DArray SkySheet;
layout (set = 0, binding = 5) uniform samplerCube SkyCube;
layout (push_constant) uniform PushConstants {
float time;
@ -12,8 +12,7 @@ layout (push_constant) uniform PushConstants {
};
layout (location = 0) in vec4 tl_st;
layout (location = 1) in vec4 color;
layout (location = 2) out vec3 direction;
layout (location = 1) in vec3 direction;
layout (location = 0) out vec4 frag_color;
@ -111,7 +110,7 @@ main (void)
if (doSkyCube || doSkySheet) {
c = sky_color (direction, time);
} else {
c = texture (Texture, t_st) * color;
c = texture (Texture, t_st);
}
if (doLight) {
c *= texture (Lightmap, l_st);

View file

@ -12,11 +12,9 @@ layout (push_constant) uniform PushConstants {
layout (location = 0) in vec4 vertex;
layout (location = 1) in vec4 tl_uv;
layout (location = 2) in vec4 vcolor;
layout (location = 0) out vec4 tl_st;
layout (location = 1) out vec4 color;
layout (location = 2) out vec3 direction;
layout (location = 1) out vec3 direction;
void
main (void)
@ -24,5 +22,4 @@ main (void)
gl_Position = Projection * (View * (Model * vertex));
direction = (Sky * vertex).xyz;
tl_st = tl_uv;
color = vcolor;
}

View file

@ -135,6 +135,12 @@ QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format)
return scrap;
}
size_t
QFV_ScrapSize (scrap_t *scrap)
{
return scrap->rscrap.width * scrap->rscrap.height * scrap->bpp;
}
void
QFV_ScrapClear (scrap_t *scrap)
{

File diff suppressed because it is too large Load diff

View file

@ -404,7 +404,6 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx)
__auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts);
for (size_t i = 0; i < frames; i++) {
__auto_type cframe = &ctx->framebuffers.a[i];
__auto_type dframe = &dctx->frames.a[i];
dframe->descriptors = sets->a[i];
@ -420,7 +419,6 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx)
};
dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0);
dframe->cmd = cmdBuffers->a[i];
DARRAY_APPEND (cframe->subCommand, cmdBuffers->a[i]);
}
free (sets);
}
@ -686,6 +684,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx)
drawframe_t *dframe = &dctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = dframe->cmd;
DARRAY_APPEND (cframe->subCommand, cmd);
VkMappedMemoryRange range = {
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,

View file

@ -0,0 +1,279 @@
/*
vulkan_lightmap.c
surface-related refresh code
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2000 Joseph Carter <knghtbrd@debian.org>
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
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
#define NH_DEFINE
#include "namehack.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <math.h>
#include <stdio.h>
#include "QF/cvar.h"
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/Vulkan/qf_bsp.h"
#include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_main.h"
#include "QF/Vulkan/texture.h"
#include "compat.h"
#include "r_internal.h"
#include "vid_vulkan.h"
#define LUXEL_SIZE 4
static inline void
add_dynamic_lights (msurface_t *surf, float *block)
{
unsigned lnum;
int sd, td;
float dist, rad, minlight;
vec3_t impact, local, lightorigin;
int smax, tmax;
int s, t;
mtexinfo_t *tex;
plane_t *plane;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
tex = surf->texinfo;
plane = surf->plane;
for (lnum = 0; lnum < r_maxdlights; lnum++) {
if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32))))
continue; // not lit by this light
dlight_t *light = &r_dlights[lnum];
VectorSubtract (light->origin, currententity->origin, lightorigin);
rad = light->radius;
dist = DotProduct (lightorigin, plane->normal) - plane->dist;
rad -= fabs (dist);
minlight = light->minlight;
if (rad < minlight) {
continue;
}
VectorMultSub (light->origin, dist, plane->normal, impact);
local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
local[0] -= surf->texturemins[0];
local[1] -= surf->texturemins[1];
for (t = 0; t < tmax; t++) {
td = local[1] - t * 16;
if (td < 0) {
td = -td;
}
for (s = 0; s < smax; s++) {
sd = local[0] - s * 16;
if (sd < 0) {
sd = -sd;
}
if (sd > td) {
dist = sd + (td >> 1);
} else {
dist = td + (sd >> 1);
}
if (dist < minlight) {
float *out = block + (t * smax + s) * LUXEL_SIZE;
float l = (rad - dist) * 256;
VectorMultAdd (out, l, light->color, out);
out[3] = 1;
out += LUXEL_SIZE;
}
}
}
}
}
void
Vulkan_BuildLightMap (msurface_t *surf, vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
int smax, tmax, size;
unsigned scale;
int i;
float *out, *block;
surf->cached_dlight = (surf->dlightframe == r_framecount);
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
size = smax * tmax * LUXEL_SIZE;
block = QFV_SubpicBatch (surf->lightpic, bctx->light_stage);
// set to full bright if no light data
if (!r_worldentity.model->lightdata) {
out = block;
while (size-- > 0) {
*out++ = 1;
}
return;
}
// clear to no light
memset (block, 0, size * sizeof(float));
// add all the lightmaps
if (surf->samples) {
byte *lightmap;
lightmap = surf->samples;
for (int maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255;
maps++) {
scale = d_lightstylevalue[surf->styles[maps]];
surf->cached_light[maps] = scale; // 8.8 fraction
out = block;
for (i = 0; i < smax * tmax; i++) {
*out++ += *lightmap++ * scale / 256.0;
*out++ += *lightmap++ * scale / 256.0;
*out++ += *lightmap++ * scale / 256.0;
}
}
}
// add all the dynamic lights
if (surf->dlightframe == r_framecount) {
add_dynamic_lights (surf, block);
}
}
void
Vulkan_CalcLightmaps (vulkan_ctx_t *ctx)
{
/* int i;
for (i = 0; i < MAX_LIGHTMAPS; i++) {
if (!gl_lightmap_polys[i])
continue;
if (gl_lightmap_modified[i]) {
qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures + i);
GL_UploadLightmap (i);
gl_lightmap_modified[i] = false;
}
}*/
}
static void
vulkan_create_surf_lightmap (msurface_t *surf, vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
int smax, tmax;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
surf->lightpic = QFV_ScrapSubpic (bctx->light_scrap, smax, tmax);
if (!surf->lightpic) {
Sys_Error ("FIXME taniwha is being lazy");
}
}
/*
GL_BuildLightmaps
Builds the lightmap texture with all the surfaces from all brush models
*/
void
Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
int i, j;
model_t *m;
QFV_ScrapClear (bctx->light_scrap);
r_framecount = 1; // no dlightcache
for (j = 1; j < num_models; j++) {
m = models[j];
if (!m)
break;
if (m->name[0] == '*') {
// sub model surfaces are processed as part of the main model
continue;
}
// non-bsp models don't have surfaces.
for (i = 0; i < m->numsurfaces; i++) {
msurface_t *surf = m->surfaces + i;
surf->lightpic = 0; // paranoia
if (surf->flags & SURF_DRAWTURB) {
continue;
}
if (surf->flags & SURF_DRAWSKY) {
continue;
}
vulkan_create_surf_lightmap (surf, ctx);
}
}
for (j = 1; j < num_models; j++) {
m = models[j];
if (!m) {
break;
}
if (m->name[0] == '*') {
// sub model surfaces are processed as part of the main model
continue;
}
// non-bsp models don't have surfaces.
for (i = 0; i < m->numsurfaces; i++) {
msurface_t *surf = m->surfaces + i;
if (surf->lightpic) {
Vulkan_BuildLightMap (surf, ctx);
}
}
}
}
VkImageView
Vulkan_LightmapImageView (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
return QFV_ScrapImageView (bctx->light_scrap);
}
void
Vulkan_FlushLightmaps (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
QFV_ScrapFlush (bctx->light_scrap);
}

View file

@ -0,0 +1,250 @@
/*
vulkan_main.c
Vulkan rendering
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2021/1/19
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
#define NH_DEFINE
#include "namehack.h"
#ifdef HAVE_STRING_H
# include "string.h"
#endif
#ifdef HAVE_STRINGS_H
# include "strings.h"
#endif
#include "QF/cmd.h"
#include "QF/cvar.h"
#include "QF/image.h"
#include "QF/render.h"
#include "QF/screen.h"
#include "QF/sys.h"
#include "QF/Vulkan/qf_vid.h"
//#include "QF/Vulkan/qf_alias.h"
#include "QF/Vulkan/qf_bsp.h"
//#include "QF/Vulkan/qf_iqm.h"
#include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_main.h"
#include "QF/Vulkan/qf_particles.h"
//#include "QF/Vulkan/qf_textures.h"
#include "mod_internal.h"
#include "r_internal.h"
#include "vid_vulkan.h"
static void
setup_frame (vulkan_ctx_t *ctx)
{
R_AnimateLight ();
R_ClearEnts ();
r_framecount++;
VectorCopy (r_refdef.vieworg, r_origin);
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
R_SetFrustum ();
r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model);
}
static void
setup_view (vulkan_ctx_t *ctx)
{
float *mat = ctx->matrices.view_3d;
static mat4_t z_up = {
0, 0, -1, 0,
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 0, 1,
};
/*x = r_refdef.vrect.x;
y = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height));
w = r_refdef.vrect.width;
h = r_refdef.vrect.height;
qfeglViewport (x, y, w, h);*/
Mat4Zero (mat);
VectorCopy (vpn, mat + 0);
VectorNegate (vright, mat + 4); // we want vleft
VectorCopy (vup, mat + 8);
mat[15] = 1;
Mat4Transpose (mat, mat);//AngleVectors gives the transpose of what we want
Mat4Mult (z_up, mat, glsl_view);
Mat4Identity (mat);
VectorNegate (r_refdef.vieworg, mat + 12);
Mat4Mult (glsl_view, mat, glsl_view);
}
static void
R_RenderEntities (vulkan_ctx_t *ctx)
{
//entity_t *ent;
//int begun;
if (!r_drawentities->int_val)
return;
#define RE_LOOP(type_name, Type) \
do { \
begun = 0; \
for (ent = r_ent_queue; ent; ent = ent->next) { \
if (ent->model->type != mod_##type_name) \
continue; \
if (!begun) { \
glsl_R_##Type##Begin (); \
begun = 1; \
} \
currententity = ent; \
glsl_R_Draw##Type (); \
} \
if (begun) \
glsl_R_##Type##End (); \
} while (0)
//RE_LOOP (alias, Alias);
//RE_LOOP (iqm, IQM);
//RE_LOOP (sprite, Sprite);
}
static void
R_DrawViewModel (void)
{
currententity = vr_data.view_model;
if (vr_data.inhibit_viewmodel
|| !r_drawviewmodel->int_val
|| !r_drawentities->int_val
|| !currententity->model)
return;
// hack the depth range to prevent view model from poking into walls
//qfeglDepthRangef (0, 0.3);
//glsl_R_AliasBegin ();
//glsl_R_DrawAlias ();
//glsl_R_AliasEnd ();
//qfeglDepthRangef (0, 1);
}
void
Vulkan_RenderView (vulkan_ctx_t *ctx)
{
double t[10] = {};
int speeds = r_speeds->int_val;
if (speeds)
t[0] = Sys_DoubleTime ();
setup_frame (ctx);
setup_view (ctx);
if (speeds)
t[1] = Sys_DoubleTime ();
R_MarkLeaves ();
if (speeds)
t[2] = Sys_DoubleTime ();
R_PushDlights (vec3_origin);
if (speeds)
t[3] = Sys_DoubleTime ();
Vulkan_DrawWorld (ctx);
if (speeds)
t[4] = Sys_DoubleTime ();
Vulkan_DrawSky (ctx);
if (speeds)
t[5] = Sys_DoubleTime ();
R_RenderEntities (ctx);
if (speeds)
t[6] = Sys_DoubleTime ();
Vulkan_DrawWaterSurfaces (ctx);
if (speeds)
t[7] = Sys_DoubleTime ();
Vulkan_DrawParticles (ctx);
if (speeds)
t[8] = Sys_DoubleTime ();
R_DrawViewModel ();
if (speeds)
t[9] = Sys_DoubleTime ();
if (speeds) {
Sys_Printf ("frame: %g, setup: %g, mark: %g, pushdl: %g, world: %g,"
" sky: %g, ents: %g, water: %g, part: %g, view: %g\n",
(t[9] - t[0]) * 1000, (t[1] - t[0]) * 1000,
(t[2] - t[1]) * 1000, (t[3] - t[2]) * 1000,
(t[4] - t[3]) * 1000, (t[5] - t[4]) * 1000,
(t[6] - t[5]) * 1000, (t[7] - t[6]) * 1000,
(t[8] - t[7]) * 1000, (t[9] - t[8]) * 1000);
}
}
void
Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models,
vulkan_ctx_t *ctx)
{
int i;
for (i = 0; i < 256; i++) {
d_lightstylevalue[i] = 264; // normal light value
}
memset (&r_worldentity, 0, sizeof (r_worldentity));
r_worldentity.model = worldmodel;
// Force a vis update
r_viewleaf = NULL;
R_MarkLeaves ();
R_FreeAllEntities ();
Vulkan_ClearParticles (ctx);
Vulkan_RegisterTextures (models, num_models, ctx);
Vulkan_BuildLightmaps (models, num_models, ctx);
Vulkan_BuildDisplayLists (models, num_models, ctx);
}
/*void
glsl_R_LineGraph (int x, int y, int *h_vals, int count)
{
}*/
/*void
glsl_R_TimeRefresh_f (void)
{
double start, stop, time;
int i;
glsl_ctx->end_rendering ();
start = Sys_DoubleTime ();
for (i = 0; i < 128; i++) {
r_refdef.viewangles[1] = i * (360.0 / 128.0);
Vulkan_RenderView (ctx);
glsl_ctx->end_rendering ();
}
stop = Sys_DoubleTime ();
time = stop - start;
Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time);
}*/