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, &region);
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(&region, 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, &region);
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