1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2007-2008 Kristian Duske
5 Copyright (C) 2010-2014 QuakeSpasm developers
6 Copyright (C) 2016 Axel Gneiting
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 */
24 // r_brush.c: brush model rendering. renamed from r_surf.c
25
26 #include "quakedef.h"
27
28 extern cvar_t gl_fullbrights, r_drawflat; //johnfitz
29
30 int gl_lightmap_format;
31 int lightmap_bytes;
32
33 #define MAX_SANITY_LIGHTMAPS (1u<<20)
34 struct lightmap_s *lightmaps;
35 int lightmap_count;
36 int last_lightmap_allocated;
37 int allocated[LMBLOCK_WIDTH];
38
39 unsigned blocklights[LMBLOCK_WIDTH*LMBLOCK_HEIGHT*3 + 1]; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (LMBLOCK_WIDTH*LMBLOCK_HEIGHT)
40
41 static vulkan_memory_t bmodel_memory;
42 VkBuffer bmodel_vertex_buffer;
43
44 extern cvar_t r_showtris;
45 extern cvar_t r_simd;
46
47 /*
48 ===============
49 R_TextureAnimation -- johnfitz -- added "frame" param to eliminate use of "currententity" global
50
51 Returns the proper texture for a given time and base texture
52 ===============
53 */
R_TextureAnimation(texture_t * base,int frame)54 texture_t *R_TextureAnimation (texture_t *base, int frame)
55 {
56 int relative;
57 int count;
58
59 if (frame)
60 if (base->alternate_anims)
61 base = base->alternate_anims;
62
63 if (!base->anim_total)
64 return base;
65
66 relative = (int)(cl.time*10) % base->anim_total;
67
68 count = 0;
69 while (base->anim_min > relative || base->anim_max <= relative)
70 {
71 base = base->anim_next;
72 if (!base)
73 Sys_Error ("R_TextureAnimation: broken cycle");
74 if (++count > 100)
75 Sys_Error ("R_TextureAnimation: infinite cycle");
76 }
77
78 return base;
79 }
80
81 /*
82 ================
83 DrawGLPoly
84 ================
85 */
DrawGLPoly(glpoly_t * p,float color[3],float alpha)86 void DrawGLPoly (glpoly_t *p, float color[3], float alpha)
87 {
88 const int numverts = p->numverts;
89 const int numtriangles = (numverts - 2);
90 const int numindices = numtriangles * 3;
91
92 VkBuffer vertex_buffer;
93 VkDeviceSize vertex_buffer_offset;
94
95 basicvertex_t * vertices = (basicvertex_t*)R_VertexAllocate(numverts * sizeof(basicvertex_t), &vertex_buffer, &vertex_buffer_offset);
96
97 float *v;
98 int i;
99 int current_index = 0;
100
101 v = p->verts[0];
102 for (i = 0; i < numverts; ++i, v += VERTEXSIZE)
103 {
104 vertices[i].position[0] = v[0];
105 vertices[i].position[1] = v[1];
106 vertices[i].position[2] = v[2];
107 vertices[i].texcoord[0] = v[3];
108 vertices[i].texcoord[1] = v[4];
109 vertices[i].color[0] = color[0] * 255.0f;
110 vertices[i].color[1] = color[1] * 255.0f;
111 vertices[i].color[2] = color[2] * 255.0f;
112 vertices[i].color[3] = alpha * 255.0f;
113 }
114
115 // I don't know the maximum poly size quake maps can have, so just in case fall back to dynamic allocations
116 // TODO: Find out if it's necessary
117 if (numindices > FAN_INDEX_BUFFER_SIZE)
118 {
119 VkBuffer index_buffer;
120 VkDeviceSize index_buffer_offset;
121
122 uint16_t * indices = (uint16_t *)R_IndexAllocate(numindices * sizeof(uint16_t), &index_buffer, &index_buffer_offset);
123 for (i = 0; i < numtriangles; ++i)
124 {
125 indices[current_index++] = 0;
126 indices[current_index++] = 1 + i;
127 indices[current_index++] = 2 + i;
128 }
129 vulkan_globals.vk_cmd_bind_index_buffer(vulkan_globals.command_buffer, index_buffer, index_buffer_offset, VK_INDEX_TYPE_UINT16);
130 }
131 else
132 vulkan_globals.vk_cmd_bind_index_buffer(vulkan_globals.command_buffer, vulkan_globals.fan_index_buffer, 0, VK_INDEX_TYPE_UINT16);
133
134 vulkan_globals.vk_cmd_bind_vertex_buffers(vulkan_globals.command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset);
135 vulkan_globals.vk_cmd_draw_indexed(vulkan_globals.command_buffer, numindices, 1, 0, 0, 0);
136 }
137
138 /*
139 =============================================================
140
141 BRUSH MODELS
142
143 =============================================================
144 */
145
146 /*
147 =================
148 R_DrawBrushModel
149 =================
150 */
R_DrawBrushModel(entity_t * e)151 void R_DrawBrushModel (entity_t *e)
152 {
153 int i, k;
154 msurface_t *psurf;
155 float dot;
156 mplane_t *pplane;
157 qmodel_t *clmodel;
158
159 if (R_CullModelForEntity(e))
160 return;
161
162 currententity = e;
163 clmodel = e->model;
164
165 VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
166 if (e->angles[0] || e->angles[1] || e->angles[2])
167 {
168 vec3_t temp;
169 vec3_t forward, right, up;
170
171 VectorCopy (modelorg, temp);
172 AngleVectors (e->angles, forward, right, up);
173 modelorg[0] = DotProduct (temp, forward);
174 modelorg[1] = -DotProduct (temp, right);
175 modelorg[2] = DotProduct (temp, up);
176 }
177
178 psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
179
180 // calculate dynamic lighting for bmodel if it's not an
181 // instanced model
182 if (clmodel->firstmodelsurface != 0)
183 {
184 for (k=0 ; k<MAX_DLIGHTS ; k++)
185 {
186 if ((cl_dlights[k].die < cl.time) ||
187 (!cl_dlights[k].radius))
188 continue;
189
190 R_MarkLights (&cl_dlights[k], k,
191 clmodel->nodes + clmodel->hulls[0].firstclipnode);
192 }
193 }
194
195 e->angles[0] = -e->angles[0]; // stupid quake bug
196 float model_matrix[16];
197 IdentityMatrix(model_matrix);
198 R_RotateForEntity (model_matrix, e->origin, e->angles);
199 e->angles[0] = -e->angles[0]; // stupid quake bug
200
201 float mvp[16];
202 memcpy(mvp, vulkan_globals.view_projection_matrix, 16 * sizeof(float));
203 MatrixMultiply(mvp, model_matrix);
204
205 R_PushConstants(VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof(float), mvp);
206 R_ClearTextureChains (clmodel, chain_model);
207 for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
208 {
209 pplane = psurf->plane;
210 dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
211 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
212 (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
213 {
214 R_ChainSurface (psurf, chain_model);
215 R_RenderDynamicLightmaps(psurf);
216 rs_brushpolys++;
217 }
218 }
219
220 R_DrawTextureChains (clmodel, e, chain_model);
221 R_DrawTextureChains_Water (clmodel, e, chain_model);
222 R_PushConstants(VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof(float), vulkan_globals.view_projection_matrix);
223 }
224
225 /*
226 =================
227 R_DrawBrushModel_ShowTris -- johnfitz
228 =================
229 */
R_DrawBrushModel_ShowTris(entity_t * e)230 void R_DrawBrushModel_ShowTris(entity_t *e)
231 {
232 int i;
233 msurface_t *psurf;
234 float dot;
235 mplane_t *pplane;
236 qmodel_t *clmodel;
237 float color[] = { 1.0f, 1.0f, 1.0f };
238 const float alpha = 1.0f;
239
240 if (R_CullModelForEntity(e))
241 return;
242
243 currententity = e;
244 clmodel = e->model;
245
246 VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
247 if (e->angles[0] || e->angles[1] || e->angles[2])
248 {
249 vec3_t temp;
250 vec3_t forward, right, up;
251
252 VectorCopy (modelorg, temp);
253 AngleVectors (e->angles, forward, right, up);
254 modelorg[0] = DotProduct (temp, forward);
255 modelorg[1] = -DotProduct (temp, right);
256 modelorg[2] = DotProduct (temp, up);
257 }
258
259 psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
260
261 e->angles[0] = -e->angles[0]; // stupid quake bug
262 float model_matrix[16];
263 IdentityMatrix(model_matrix);
264 R_RotateForEntity (model_matrix, e->origin, e->angles);
265 e->angles[0] = -e->angles[0]; // stupid quake bug
266
267 float mvp[16];
268 memcpy(mvp, vulkan_globals.view_projection_matrix, 16 * sizeof(float));
269 MatrixMultiply(mvp, model_matrix);
270
271 if (r_showtris.value == 1)
272 R_BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.showtris_pipeline);
273 else
274 R_BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.showtris_depth_test_pipeline);
275 R_PushConstants(VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof(float), mvp);
276
277 //
278 // draw it
279 //
280 for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
281 {
282 pplane = psurf->plane;
283 dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
284 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
285 (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
286 {
287 DrawGLPoly (psurf->polys, color, alpha);
288 }
289 }
290
291 R_PushConstants(VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof(float), vulkan_globals.view_projection_matrix);
292 }
293
294 /*
295 =============================================================
296
297 LIGHTMAPS
298
299 =============================================================
300 */
301
302 /*
303 ================
304 R_RenderDynamicLightmaps
305 called during rendering
306 ================
307 */
R_RenderDynamicLightmaps(msurface_t * fa)308 void R_RenderDynamicLightmaps (msurface_t *fa)
309 {
310 byte *base;
311 int maps;
312 glRect_t *theRect;
313 int smax, tmax;
314
315 if (fa->flags & SURF_DRAWTILED) //johnfitz -- not a lightmapped surface
316 return;
317
318 // check for lightmap modification
319 for (maps=0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++)
320 if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
321 goto dynamic;
322
323 if (fa->dlightframe == r_framecount // dynamic this frame
324 || fa->cached_dlight) // dynamic previously
325 {
326 dynamic:
327 if (r_dynamic.value)
328 {
329 struct lightmap_s *lm = &lightmaps[fa->lightmaptexturenum];
330 lm->modified = true;
331 theRect = &lm->rectchange;
332 if (fa->light_t < theRect->t) {
333 if (theRect->h)
334 theRect->h += theRect->t - fa->light_t;
335 theRect->t = fa->light_t;
336 }
337 if (fa->light_s < theRect->l) {
338 if (theRect->w)
339 theRect->w += theRect->l - fa->light_s;
340 theRect->l = fa->light_s;
341 }
342 smax = (fa->extents[0]>>4)+1;
343 tmax = (fa->extents[1]>>4)+1;
344 if ((theRect->w + theRect->l) < (fa->light_s + smax))
345 theRect->w = (fa->light_s-theRect->l)+smax;
346 if ((theRect->h + theRect->t) < (fa->light_t + tmax))
347 theRect->h = (fa->light_t-theRect->t)+tmax;
348 base = lm->data;
349 base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
350 R_BuildLightMap (fa, base, LMBLOCK_WIDTH*lightmap_bytes);
351 }
352 }
353 }
354
355 /*
356 ========================
357 AllocBlock -- returns a texture number and the position inside it
358 ========================
359 */
AllocBlock(int w,int h,int * x,int * y)360 int AllocBlock (int w, int h, int *x, int *y)
361 {
362 int i, j;
363 int best, best2;
364 int texnum;
365
366 // ericw -- rather than searching starting at lightmap 0 every time,
367 // start at the last lightmap we allocated a surface in.
368 // This makes AllocBlock much faster on large levels (can shave off 3+ seconds
369 // of load time on a level with 180 lightmaps), at a cost of not quite packing
370 // lightmaps as tightly vs. not doing this (uses ~5% more lightmaps)
371 for (texnum=last_lightmap_allocated ; texnum<MAX_SANITY_LIGHTMAPS ; texnum++)
372 {
373 if (texnum == lightmap_count)
374 {
375 lightmap_count++;
376 lightmaps = (struct lightmap_s *) realloc(lightmaps, sizeof(*lightmaps)*lightmap_count);
377 memset(&lightmaps[texnum], 0, sizeof(lightmaps[texnum]));
378 lightmaps[texnum].data = (byte *) calloc(1, 4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT);
379 //as we're only tracking one texture, we don't need multiple copies of allocated any more.
380 memset(allocated, 0, sizeof(allocated));
381 }
382 best = LMBLOCK_HEIGHT;
383
384 for (i=0 ; i<LMBLOCK_WIDTH-w ; i++)
385 {
386 best2 = 0;
387
388 for (j=0 ; j<w ; j++)
389 {
390 if (allocated[i+j] >= best)
391 break;
392 if (allocated[i+j] > best2)
393 best2 = allocated[i+j];
394 }
395 if (j == w)
396 { // this is a valid spot
397 *x = i;
398 *y = best = best2;
399 }
400 }
401
402 if (best + h > LMBLOCK_HEIGHT)
403 continue;
404
405 for (i=0 ; i<w ; i++)
406 allocated[*x + i] = best + h;
407
408 last_lightmap_allocated = texnum;
409 return texnum;
410 }
411
412 Sys_Error ("AllocBlock: full");
413 return 0; //johnfitz -- shut up compiler
414 }
415
416
417 mvertex_t *r_pcurrentvertbase;
418 qmodel_t *currentmodel;
419
420 int nColinElim;
421
422 /*
423 ========================
424 GL_CreateSurfaceLightmap
425 ========================
426 */
GL_CreateSurfaceLightmap(msurface_t * surf)427 void GL_CreateSurfaceLightmap (msurface_t *surf)
428 {
429 int smax, tmax;
430 byte *base;
431
432 smax = (surf->extents[0]>>4)+1;
433 tmax = (surf->extents[1]>>4)+1;
434
435 surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
436 base = lightmaps[surf->lightmaptexturenum].data;
437 base += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * lightmap_bytes;
438 R_BuildLightMap (surf, base, LMBLOCK_WIDTH*lightmap_bytes);
439 }
440
441 /*
442 ================
443 BuildSurfaceDisplayList -- called at level load time
444 ================
445 */
BuildSurfaceDisplayList(msurface_t * fa)446 void BuildSurfaceDisplayList (msurface_t *fa)
447 {
448 int i, lindex, lnumverts;
449 medge_t *pedges, *r_pedge;
450 float *vec;
451 float s, t;
452 glpoly_t *poly;
453 float *poly_vert;
454
455 // reconstruct the polygon
456 pedges = currentmodel->edges;
457 lnumverts = fa->numedges;
458
459 //
460 // draw texture
461 //
462 poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
463 poly->next = fa->polys;
464 fa->polys = poly;
465 poly->numverts = lnumverts;
466
467 for (i=0 ; i<lnumverts ; i++)
468 {
469 lindex = currentmodel->surfedges[fa->firstedge + i];
470
471 if (lindex > 0)
472 {
473 r_pedge = &pedges[lindex];
474 vec = r_pcurrentvertbase[r_pedge->v[0]].position;
475 }
476 else
477 {
478 r_pedge = &pedges[-lindex];
479 vec = r_pcurrentvertbase[r_pedge->v[1]].position;
480 }
481 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
482 s /= fa->texinfo->texture->width;
483
484 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
485 t /= fa->texinfo->texture->height;
486
487 poly_vert = &poly->verts[0][0] + (i * VERTEXSIZE);
488 VectorCopy (vec, poly_vert);
489 poly_vert[3] = s;
490 poly_vert[4] = t;
491
492 // Q64 RERELEASE texture shift
493 if (fa->texinfo->texture->shift > 0)
494 {
495 poly_vert[3] /= ( 2 * fa->texinfo->texture->shift);
496 poly_vert[4] /= ( 2 * fa->texinfo->texture->shift);
497 }
498
499 //
500 // lightmap texture coordinates
501 //
502 s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
503 s -= fa->texturemins[0];
504 s += fa->light_s*16;
505 s += 8;
506 s /= LMBLOCK_WIDTH*16; //fa->texinfo->texture->width;
507
508 t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
509 t -= fa->texturemins[1];
510 t += fa->light_t*16;
511 t += 8;
512 t /= LMBLOCK_HEIGHT*16; //fa->texinfo->texture->height;
513
514 poly_vert[5] = s;
515 poly_vert[6] = t;
516 }
517
518 //johnfitz -- removed gl_keeptjunctions code
519
520 poly->numverts = lnumverts;
521 }
522
523 /*
524 ==================
525 GL_BuildLightmaps -- called at level load time
526
527 Builds the lightmap texture
528 with all the surfaces from all brush models
529 ==================
530 */
GL_BuildLightmaps(void)531 void GL_BuildLightmaps (void)
532 {
533 char name[24];
534 int i, j;
535 struct lightmap_s *lm;
536 qmodel_t *m;
537
538 r_framecount = 1; // no dlightcache
539
540 //Spike -- wipe out all the lightmap data (johnfitz -- the gltexture objects were already freed by Mod_ClearAll)
541 for (i=0; i < lightmap_count; i++)
542 free(lightmaps[i].data);
543 free(lightmaps);
544 lightmaps = NULL;
545 last_lightmap_allocated = 0;
546 lightmap_count = 0;
547
548 lightmap_bytes = 4;
549
550 for (j=1 ; j<MAX_MODELS ; j++)
551 {
552 m = cl.model_precache[j];
553 if (!m)
554 break;
555 if (m->name[0] == '*')
556 continue;
557 r_pcurrentvertbase = m->vertexes;
558 currentmodel = m;
559 for (i=0 ; i<m->numsurfaces ; i++)
560 {
561 //johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
562 if (m->surfaces[i].flags & SURF_DRAWTILED)
563 continue;
564 GL_CreateSurfaceLightmap (m->surfaces + i);
565 BuildSurfaceDisplayList (m->surfaces + i);
566 //johnfitz
567 }
568 }
569
570 //
571 // upload all lightmaps that were filled
572 //
573 for (i=0; i<lightmap_count; i++)
574 {
575 lm = &lightmaps[i];
576 lm->modified = false;
577 lm->rectchange.l = LMBLOCK_WIDTH;
578 lm->rectchange.t = LMBLOCK_HEIGHT;
579 lm->rectchange.w = 0;
580 lm->rectchange.h = 0;
581
582 //johnfitz -- use texture manager
583 sprintf(name, "lightmap%07i",i);
584 lm->texture = TexMgr_LoadImage (cl.worldmodel, name, LMBLOCK_WIDTH, LMBLOCK_HEIGHT,
585 SRC_LIGHTMAP, lm->data, "", (src_offset_t)lm->data, TEXPREF_LINEAR | TEXPREF_NOPICMIP);
586 //johnfitz
587 }
588
589 //johnfitz -- warn about exceeding old limits
590 //GLQuake limit was 64 textures of 128x128. Estimate how many 128x128 textures we would need
591 //given that we are using lightmap_count of LMBLOCK_WIDTH x LMBLOCK_HEIGHT
592 i = lightmap_count * ((LMBLOCK_WIDTH / 128) * (LMBLOCK_HEIGHT / 128));
593 if (i > 64)
594 Con_DWarning("%i lightmaps exceeds standard limit of 64.\n",i);
595 //johnfitz
596 }
597
598 /*
599 =============================================================
600
601 VBO support
602
603 =============================================================
604 */
605
GL_DeleteBModelVertexBuffer(void)606 void GL_DeleteBModelVertexBuffer (void)
607 {
608 GL_WaitForDeviceIdle();
609
610 if (bmodel_vertex_buffer)
611 vkDestroyBuffer(vulkan_globals.device, bmodel_vertex_buffer, NULL);
612
613 if (bmodel_memory.handle != VK_NULL_HANDLE)
614 {
615 num_vulkan_bmodel_allocations -= 1;
616 R_FreeVulkanMemory(&bmodel_memory);
617 }
618 }
619
620 /*
621 ==================
622 GL_BuildBModelVertexBuffer
623
624 Deletes gl_bmodel_vbo if it already exists, then rebuilds it with all
625 surfaces from world + all brush models
626 ==================
627 */
GL_BuildBModelVertexBuffer(void)628 void GL_BuildBModelVertexBuffer (void)
629 {
630 unsigned int numverts, varray_bytes, varray_index;
631 int i, j;
632 qmodel_t *m;
633 float *varray;
634 int remaining_size;
635 int copy_offset;
636
637 // count all verts in all models
638 numverts = 0;
639 for (j=1 ; j<MAX_MODELS ; j++)
640 {
641 m = cl.model_precache[j];
642 if (!m || m->name[0] == '*' || m->type != mod_brush)
643 continue;
644
645 for (i=0 ; i<m->numsurfaces ; i++)
646 {
647 numverts += m->surfaces[i].numedges;
648 }
649 }
650
651 // build vertex array
652 varray_bytes = VERTEXSIZE * sizeof(float) * numverts;
653 varray = (float *) malloc (varray_bytes);
654 varray_index = 0;
655
656 for (j=1 ; j<MAX_MODELS ; j++)
657 {
658 m = cl.model_precache[j];
659 if (!m || m->name[0] == '*' || m->type != mod_brush)
660 continue;
661
662 for (i=0 ; i<m->numsurfaces ; i++)
663 {
664 msurface_t *s = &m->surfaces[i];
665 s->vbo_firstvert = varray_index;
666 memcpy (&varray[VERTEXSIZE * varray_index], s->polys->verts, VERTEXSIZE * sizeof(float) * s->numedges);
667 varray_index += s->numedges;
668 }
669 }
670
671 // Allocate & upload to GPU
672 VkResult err;
673
674 VkBufferCreateInfo buffer_create_info;
675 memset(&buffer_create_info, 0, sizeof(buffer_create_info));
676 buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
677 buffer_create_info.size = varray_bytes;
678 buffer_create_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
679 err = vkCreateBuffer(vulkan_globals.device, &buffer_create_info, NULL, &bmodel_vertex_buffer);
680 if (err != VK_SUCCESS)
681 Sys_Error("vkCreateBuffer failed");
682
683 GL_SetObjectName((uint64_t)bmodel_vertex_buffer, VK_OBJECT_TYPE_BUFFER, "Brush Vertex Buffer");
684
685 VkMemoryRequirements memory_requirements;
686 vkGetBufferMemoryRequirements(vulkan_globals.device, bmodel_vertex_buffer, &memory_requirements);
687
688 const int align_mod = memory_requirements.size % memory_requirements.alignment;
689 const int aligned_size = ((memory_requirements.size % memory_requirements.alignment) == 0 )
690 ? memory_requirements.size
691 : (memory_requirements.size + memory_requirements.alignment - align_mod);
692
693 VkMemoryAllocateInfo memory_allocate_info;
694 memset(&memory_allocate_info, 0, sizeof(memory_allocate_info));
695 memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
696 memory_allocate_info.allocationSize = aligned_size;
697 memory_allocate_info.memoryTypeIndex = GL_MemoryTypeFromProperties(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
698
699 num_vulkan_bmodel_allocations += 1;
700 R_AllocateVulkanMemory(&bmodel_memory, &memory_allocate_info, VULKAN_MEMORY_TYPE_DEVICE);
701 GL_SetObjectName((uint64_t)bmodel_memory.handle, VK_OBJECT_TYPE_DEVICE_MEMORY, "Brush Memory");
702
703 err = vkBindBufferMemory(vulkan_globals.device, bmodel_vertex_buffer, bmodel_memory.handle, 0);
704 if (err != VK_SUCCESS)
705 Sys_Error("vkBindImageMemory failed");
706
707 remaining_size = varray_bytes;
708 copy_offset = 0;
709
710 while (remaining_size > 0)
711 {
712 const int size_to_copy = q_min(remaining_size, vulkan_globals.staging_buffer_size);
713 VkBuffer staging_buffer;
714 VkCommandBuffer command_buffer;
715 int staging_offset;
716 unsigned char * staging_memory = R_StagingAllocate(size_to_copy, 1, &command_buffer, &staging_buffer, &staging_offset);
717
718 memcpy(staging_memory, (byte*)varray + copy_offset, size_to_copy);
719
720 VkBufferCopy region;
721 region.srcOffset = staging_offset;
722 region.dstOffset = copy_offset;
723 region.size = size_to_copy;
724 vkCmdCopyBuffer(command_buffer, staging_buffer, bmodel_vertex_buffer, 1, ®ion);
725
726 copy_offset += size_to_copy;
727 remaining_size -= size_to_copy;
728 }
729
730 free (varray);
731 }
732
733 /*
734 ===============
735 R_AddDynamicLights
736 ===============
737 */
R_AddDynamicLights(msurface_t * surf)738 void R_AddDynamicLights (msurface_t *surf)
739 {
740 int lnum;
741 int sd, td;
742 float dist, rad, minlight;
743 vec3_t impact, local;
744 int s, t;
745 int i;
746 int smax, tmax;
747 mtexinfo_t *tex;
748 //johnfitz -- lit support via lordhavoc
749 float cred, cgreen, cblue, brightness;
750 unsigned *bl;
751 //johnfitz
752
753 smax = (surf->extents[0]>>4)+1;
754 tmax = (surf->extents[1]>>4)+1;
755 tex = surf->texinfo;
756
757 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
758 {
759 if (! (surf->dlightbits[lnum >> 5] & (1U << (lnum & 31))))
760 continue; // not lit by this light
761
762 rad = cl_dlights[lnum].radius;
763 dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
764 surf->plane->dist;
765 rad -= fabs(dist);
766 minlight = cl_dlights[lnum].minlight;
767 if (rad < minlight)
768 continue;
769 minlight = rad - minlight;
770
771 for (i=0 ; i<3 ; i++)
772 {
773 impact[i] = cl_dlights[lnum].origin[i] -
774 surf->plane->normal[i]*dist;
775 }
776
777 local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
778 local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
779
780 local[0] -= surf->texturemins[0];
781 local[1] -= surf->texturemins[1];
782
783 //johnfitz -- lit support via lordhavoc
784 bl = blocklights;
785 cred = cl_dlights[lnum].color[0] * 256.0f;
786 cgreen = cl_dlights[lnum].color[1] * 256.0f;
787 cblue = cl_dlights[lnum].color[2] * 256.0f;
788 //johnfitz
789 for (t = 0 ; t<tmax ; t++)
790 {
791 td = local[1] - t*16;
792 if (td < 0)
793 td = -td;
794 for (s=0 ; s<smax ; s++)
795 {
796 sd = local[0] - s*16;
797 if (sd < 0)
798 sd = -sd;
799 if (sd > td)
800 dist = sd + (td>>1);
801 else
802 dist = td + (sd>>1);
803 if (dist < minlight)
804 //johnfitz -- lit support via lordhavoc
805 {
806 brightness = rad - dist;
807 bl[0] += (int) (brightness * cred);
808 bl[1] += (int) (brightness * cgreen);
809 bl[2] += (int) (brightness * cblue);
810 }
811 bl += 3;
812 //johnfitz
813 }
814 }
815 }
816 }
817
818
819 /*
820 ===============
821 R_AccumulateLightmap
822
823 Scales 'lightmap' contents (RGB8) by 'scale' and accumulates
824 the result in the 'blocklights' array (RGB32)
825 ===============
826 */
R_AccumulateLightmap(byte * lightmap,unsigned scale,int texels)827 void R_AccumulateLightmap(byte* lightmap, unsigned scale, int texels)
828 {
829 unsigned *bl = blocklights;
830 int size = texels * 3;
831
832 #ifdef USE_SSE2
833 if (use_simd && size >= 8)
834 {
835 __m128i vscale = _mm_set1_epi16(scale);
836 __m128i vlo, vhi, vdst, vsrc, v;
837
838 while (size >= 8)
839 {
840 vsrc = _mm_loadl_epi64((const __m128i*)lightmap);
841
842 v = _mm_unpacklo_epi8(vsrc, _mm_setzero_si128());
843 vlo = _mm_mullo_epi16(v, vscale);
844 vhi = _mm_mulhi_epu16(v, vscale);
845
846 vdst = _mm_loadu_si128((const __m128i*)bl);
847 vdst = _mm_add_epi32(vdst, _mm_unpacklo_epi16(vlo, vhi));
848 _mm_storeu_si128((__m128i*)bl, vdst);
849 bl += 4;
850
851 vdst = _mm_loadu_si128((const __m128i*)bl);
852 vdst = _mm_add_epi32(vdst, _mm_unpackhi_epi16(vlo, vhi));
853 _mm_storeu_si128((__m128i*)bl, vdst);
854 bl += 4;
855
856 lightmap += 8;
857 size -= 8;
858 }
859 }
860 #endif // def USE_SSE2
861
862 while (size-- > 0)
863 *bl++ += *lightmap++ * scale;
864 }
865
866 /*
867 ===============
868 R_StoreLightmap
869
870 Converts contiguous lightmap info accumulated in 'blocklights'
871 from RGB32 (with 8 fractional bits) to RGBA8, saturates and
872 stores the result in 'dest'
873 ===============
874 */
R_StoreLightmap(byte * dest,int width,int height,int stride)875 void R_StoreLightmap(byte* dest, int width, int height, int stride)
876 {
877 unsigned *src = blocklights;
878
879 #ifdef USE_SSE2
880 if (use_simd)
881 {
882 __m128i vzero = _mm_setzero_si128();
883
884 while (height-- > 0)
885 {
886 int i;
887 for (i = 0; i < width; i++)
888 {
889 __m128i v = _mm_srli_epi32(_mm_loadu_si128((const __m128i*)src), 8);
890 v = _mm_packs_epi32(v, vzero);
891 v = _mm_packus_epi16(v, vzero);
892 ((uint32_t*)dest)[i] = _mm_cvtsi128_si32(v) | 0xff000000;
893 src += 3;
894 }
895 dest += stride;
896 }
897 }
898 else
899 #endif // def USE_SSE2
900 {
901 stride -= width * 4;
902 while (height-- > 0)
903 {
904 int i;
905 for (i = 0; i < width; i++)
906 {
907 unsigned c;
908 c = *src++ >> 8; *dest++ = q_min(c, 255);
909 c = *src++ >> 8; *dest++ = q_min(c, 255);
910 c = *src++ >> 8; *dest++ = q_min(c, 255);
911 *dest++ = 255;
912 }
913 dest += stride;
914 }
915 }
916 }
917
918 /*
919 ===============
920 R_BuildLightMap -- johnfitz -- revised for lit support via lordhavoc
921
922 Combine and scale multiple lightmaps into the 8.8 format in blocklights
923 ===============
924 */
R_BuildLightMap(msurface_t * surf,byte * dest,int stride)925 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
926 {
927 int smax, tmax;
928 int size;
929 byte *lightmap;
930 unsigned scale;
931 int maps;
932
933 surf->cached_dlight = (surf->dlightframe == r_framecount);
934
935 smax = (surf->extents[0]>>4)+1;
936 tmax = (surf->extents[1]>>4)+1;
937 size = smax*tmax;
938 lightmap = surf->samples;
939
940 if (cl.worldmodel->lightdata)
941 {
942 // clear to no light
943 memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
944
945 // add all the lightmaps
946 if (lightmap)
947 {
948 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
949 maps++)
950 {
951 scale = d_lightstylevalue[surf->styles[maps]];
952 surf->cached_light[maps] = scale; // 8.8 fraction
953 //johnfitz -- lit support via lordhavoc
954 R_AccumulateLightmap(lightmap, scale, size);
955 lightmap += size * 3;
956 //johnfitz
957 }
958 }
959
960 // add all the dynamic lights
961 if (surf->dlightframe == r_framecount)
962 R_AddDynamicLights (surf);
963 }
964 else
965 {
966 // set to full bright if no light data
967 memset (&blocklights[0], 255, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
968 }
969
970 R_StoreLightmap(dest, smax, tmax, stride);
971 }
972
973 /*
974 ===============
975 R_UploadLightmap -- johnfitz -- uploads the modified lightmap to opengl if necessary
976
977 assumes lightmap texture is already bound
978 ===============
979 */
R_UploadLightmap(int lmap,gltexture_t * lightmap_tex)980 static void R_UploadLightmap(int lmap, gltexture_t * lightmap_tex)
981 {
982 struct lightmap_s *lm = &lightmaps[lmap];
983 if (!lm->modified)
984 return;
985
986 lm->modified = false;
987
988 const int staging_size = LMBLOCK_WIDTH * lm->rectchange.h * 4;
989
990 VkBuffer staging_buffer;
991 VkCommandBuffer command_buffer;
992 int staging_offset;
993 unsigned char * staging_memory = R_StagingAllocate(staging_size, 4, &command_buffer, &staging_buffer, &staging_offset);
994
995 byte * data = lm->data+lm->rectchange.t*LMBLOCK_WIDTH*lightmap_bytes;
996 memcpy(staging_memory, data, staging_size);
997
998 VkBufferImageCopy region;
999 memset(®ion, 0, sizeof(region));
1000 region.bufferOffset = staging_offset;
1001 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1002 region.imageSubresource.layerCount = 1;
1003 region.imageSubresource.mipLevel = 0;
1004 region.imageExtent.width = LMBLOCK_WIDTH;
1005 region.imageExtent.height = lm->rectchange.h;
1006 region.imageExtent.depth = 1;
1007 region.imageOffset.y = lm->rectchange.t;
1008
1009 VkImageMemoryBarrier image_memory_barrier;
1010 memset(&image_memory_barrier, 0, sizeof(image_memory_barrier));
1011 image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1012 image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
1013 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1014 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1015 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1016 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1017 image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1018 image_memory_barrier.image = lightmap_tex->image;
1019 image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1020 image_memory_barrier.subresourceRange.baseMipLevel = 0;
1021 image_memory_barrier.subresourceRange.levelCount = 1;
1022 image_memory_barrier.subresourceRange.baseArrayLayer = 0;
1023 image_memory_barrier.subresourceRange.layerCount = 1;
1024
1025 vulkan_globals.vk_cmd_pipeline_barrier(command_buffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
1026
1027 vulkan_globals.vk_cmd_copy_buffer_to_image(command_buffer, staging_buffer, lightmap_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
1028
1029 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1030 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1031 image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1032 image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
1033 vulkan_globals.vk_cmd_pipeline_barrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
1034
1035 lm->rectchange.l = LMBLOCK_WIDTH;
1036 lm->rectchange.t = LMBLOCK_HEIGHT;
1037 lm->rectchange.h = 0;
1038 lm->rectchange.w = 0;
1039
1040 rs_dynamiclightmaps++;
1041 }
1042
R_UploadLightmaps(void)1043 void R_UploadLightmaps (void)
1044 {
1045 int lmap;
1046
1047 for (lmap = 0; lmap < lightmap_count; lmap++)
1048 {
1049 if (!lightmaps[lmap].modified)
1050 continue;
1051
1052 R_UploadLightmap(lmap, lightmaps[lmap].texture);
1053 }
1054 }
1055