1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5 Copyright (C) 2016 Axel Gneiting
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 */
22 //gl_warp.c -- warping animation support
23 
24 #include "quakedef.h"
25 
26 extern cvar_t r_drawflat;
27 
28 cvar_t r_waterquality = {"r_waterquality", "8", CVAR_NONE};
29 cvar_t r_waterwarp = {"r_waterwarp", "1", CVAR_ARCHIVE};
30 cvar_t r_waterwarpcompute = { "r_waterwarpcompute", "1", CVAR_ARCHIVE };
31 
32 float	turbsin[] =
33 {
34 #include "gl_warp_sin.h"
35 };
36 
37 #define WARPCALC(s,t) ((s + turbsin[(int)((t*2)+(cl.time*(128.0/M_PI))) & 255]) * (1.0/64)) //johnfitz -- correct warp
38 
39 //==============================================================================
40 //
41 //  OLD-STYLE WATER
42 //
43 //==============================================================================
44 
45 extern	qmodel_t	*loadmodel;
46 
47 msurface_t	*warpface;
48 
49 cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", CVAR_ARCHIVE};
50 
BoundPoly(int numverts,float * verts,vec3_t mins,vec3_t maxs)51 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
52 {
53 	int		i, j;
54 	float	*v;
55 
56 	mins[0] = mins[1] = mins[2] = FLT_MAX;
57 	maxs[0] = maxs[1] = maxs[2] = -FLT_MAX;
58 	v = verts;
59 	for (i=0 ; i<numverts ; i++)
60 		for (j=0 ; j<3 ; j++, v++)
61 		{
62 			if (*v < mins[j])
63 				mins[j] = *v;
64 			if (*v > maxs[j])
65 				maxs[j] = *v;
66 		}
67 }
68 
SubdividePolygon(int numverts,float * verts)69 void SubdividePolygon (int numverts, float *verts)
70 {
71 	int		i, j, k;
72 	vec3_t	mins, maxs;
73 	float	m;
74 	float	*v;
75 	vec3_t	front[64], back[64];
76 	int		f, b;
77 	float	dist[64];
78 	float	frac;
79 	glpoly_t	*poly;
80 	float	*poly_vert;
81 	float	s, t;
82 
83 	if (numverts > 60)
84 		Sys_Error ("numverts = %i", numverts);
85 
86 	BoundPoly (numverts, verts, mins, maxs);
87 
88 	for (i=0 ; i<3 ; i++)
89 	{
90 		m = (mins[i] + maxs[i]) * 0.5;
91 		m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);
92 		if (maxs[i] - m < 8)
93 			continue;
94 		if (m - mins[i] < 8)
95 			continue;
96 
97 		// cut it
98 		v = verts + i;
99 		for (j=0 ; j<numverts ; j++, v+= 3)
100 			dist[j] = *v - m;
101 
102 		// wrap cases
103 		dist[j] = dist[0];
104 		v-=i;
105 		VectorCopy (verts, v);
106 
107 		f = b = 0;
108 		v = verts;
109 		for (j=0 ; j<numverts ; j++, v+= 3)
110 		{
111 			if (dist[j] >= 0)
112 			{
113 				VectorCopy (v, front[f]);
114 				f++;
115 			}
116 			if (dist[j] <= 0)
117 			{
118 				VectorCopy (v, back[b]);
119 				b++;
120 			}
121 			if (dist[j] == 0 || dist[j+1] == 0)
122 				continue;
123 			if ( (dist[j] > 0) != (dist[j+1] > 0) )
124 			{
125 				// clip point
126 				frac = dist[j] / (dist[j] - dist[j+1]);
127 				for (k=0 ; k<3 ; k++)
128 					front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);
129 				f++;
130 				b++;
131 			}
132 		}
133 
134 		SubdividePolygon (f, front[0]);
135 		SubdividePolygon (b, back[0]);
136 		return;
137 	}
138 
139 	poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));
140 	poly->next = warpface->polys->next;
141 	warpface->polys->next = poly;
142 	poly->numverts = numverts;
143 	for (i=0 ; i<numverts ; i++, verts+= 3)
144 	{
145 		poly_vert = &poly->verts[0][0] + (i * VERTEXSIZE);
146 		VectorCopy (verts, poly_vert);
147 		s = DotProduct (verts, warpface->texinfo->vecs[0]);
148 		t = DotProduct (verts, warpface->texinfo->vecs[1]);
149 		poly_vert[3] = s;
150 		poly_vert[4] = t;
151 	}
152 }
153 
154 /*
155 ================
156 GL_SubdivideSurface
157 ================
158 */
GL_SubdivideSurface(msurface_t * fa)159 void GL_SubdivideSurface (msurface_t *fa)
160 {
161 	vec3_t	verts[64];
162 	int		i;
163 	float *poly_vert;
164 
165 	warpface = fa;
166 
167 	//the first poly in the chain is the undivided poly for newwater rendering.
168 	//grab the verts from that.
169 	for (i=0; i<fa->polys->numverts; i++)
170 	{
171 		poly_vert = &fa->polys->verts[0][0] + (i * VERTEXSIZE);
172 		VectorCopy (poly_vert, verts[i]);
173 	}
174 
175 	SubdividePolygon (fa->polys->numverts, verts[0]);
176 }
177 
178 //==============================================================================
179 //
180 //  RENDER-TO-FRAMEBUFFER WATER
181 //
182 //==============================================================================
R_RasterWarpTexture(texture_t * tx,float warptess)183 static void R_RasterWarpTexture(texture_t *tx, float warptess) {
184 	float x, y, x2;
185 
186 	VkRect2D render_area;
187 	render_area.offset.x = 0;
188 	render_area.offset.y = 0;
189 	render_area.extent.width = WARPIMAGESIZE;
190 	render_area.extent.height = WARPIMAGESIZE;
191 
192 	VkRenderPassBeginInfo render_pass_begin_info;
193 	memset(&render_pass_begin_info, 0, sizeof(render_pass_begin_info));
194 	render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
195 	render_pass_begin_info.renderArea = render_area;
196 	render_pass_begin_info.renderPass = vulkan_globals.warp_render_pass;
197 	render_pass_begin_info.framebuffer = tx->warpimage->frame_buffer;
198 
199 	vkCmdBeginRenderPass(vulkan_globals.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
200 
201 	//render warp
202 	GL_SetCanvas(CANVAS_WARPIMAGE);
203 	R_BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.raster_tex_warp_pipeline);
204 	if (!r_lightmap_cheatsafe)
205 		vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_pipeline_layout.handle, 0, 1, &tx->gltexture->descriptor_set, 0, NULL);
206 	else
207 		vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_pipeline_layout.handle, 0, 1, &whitetexture->descriptor_set, 0, NULL);
208 
209 	int num_verts = 0;
210 	for (y = 0.0; y<128.01; y += warptess) // .01 for rounding errors
211 		num_verts += 2;
212 
213 	for (x = 0.0; x<128.0; x = x2)
214 	{
215 		VkBuffer buffer;
216 		VkDeviceSize buffer_offset;
217 		basicvertex_t * vertices = (basicvertex_t*)R_VertexAllocate(num_verts * sizeof(basicvertex_t), &buffer, &buffer_offset);
218 
219 		int i = 0;
220 		x2 = x + warptess;
221 		for (y = 0.0; y<128.01; y += warptess) // .01 for rounding errors
222 		{
223 			vertices[i].position[0] = x;
224 			vertices[i].position[1] = y;
225 			vertices[i].position[2] = 0.0f;
226 			vertices[i].texcoord[0] = WARPCALC(x, y);
227 			vertices[i].texcoord[1] = 1.0f - WARPCALC(y, x);
228 			vertices[i].color[0] = 255;
229 			vertices[i].color[1] = 255;
230 			vertices[i].color[2] = 255;
231 			vertices[i].color[3] = 255;
232 			i += 1;
233 			vertices[i].position[0] = x2;
234 			vertices[i].position[1] = y;
235 			vertices[i].position[2] = 0.0f;
236 			vertices[i].texcoord[0] = WARPCALC(x2, y);
237 			vertices[i].texcoord[1] = 1.0f - WARPCALC(y, x2);
238 			vertices[i].color[0] = 255;
239 			vertices[i].color[1] = 255;
240 			vertices[i].color[2] = 255;
241 			vertices[i].color[3] = 255;
242 			i += 1;
243 		}
244 
245 		vkCmdBindVertexBuffers(vulkan_globals.command_buffer, 0, 1, &buffer, &buffer_offset);
246 		vkCmdDraw(vulkan_globals.command_buffer, num_verts, 1, 0, 0);
247 	}
248 
249 	vkCmdEndRenderPass(vulkan_globals.command_buffer);
250 }
251 
252 /*
253 =============
254 R_ComputeWarpTexture
255 =============
256 */
R_ComputeWarpTexture(texture_t * tx,float warptess)257 static void R_ComputeWarpTexture(texture_t *tx, float warptess) {
258 	//render warp
259 	const float time = cl.time;
260 	R_BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_globals.cs_tex_warp_pipeline);
261 	VkDescriptorSet sets[2] = { tx->gltexture->descriptor_set, tx->warpimage->warp_write_descriptor_set };
262 	if (r_lightmap_cheatsafe)
263 		sets[0] = whitetexture->descriptor_set;
264 	vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_globals.cs_tex_warp_pipeline.layout.handle, 0, 2, sets, 0, NULL);
265 	R_PushConstants(VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time);
266 	vkCmdDispatch(vulkan_globals.command_buffer, WARPIMAGESIZE / 8, WARPIMAGESIZE / 8, 1);
267 }
268 
269 /*
270 =============
271 R_UpdateWarpTextures -- johnfitz -- each frame, update warping textures
272 =============
273 */
274 static texture_t * warp_textures[MAX_GLTEXTURES];
275 static VkImageMemoryBarrier warp_image_barriers[MAX_GLTEXTURES];
276 
R_UpdateWarpTextures(void)277 void R_UpdateWarpTextures (void)
278 {
279 	GL_SetCanvas(CANVAS_NONE); // Invalidate canvas so push constants get set later
280 
281 	texture_t *tx;
282 	int i, mip;
283 	float warptess;
284 
285 	if (cl.paused)
286 		return;
287 
288 	R_BeginDebugUtilsLabel ("Update Warp Textures");
289 
290 	warptess = 128.0/CLAMP (3.0, floor(r_waterquality.value), 64.0);
291 
292 	int num_textures = cl.worldmodel->numtextures;
293 	int num_warp_textures = 0;
294 
295 	// Count warp texture & prepare barrier from undefined to GENERL if using compute warp
296 	for (i = 0; i < num_textures; ++i)
297 	{
298 		if (!(tx = cl.worldmodel->textures[i]))
299 			continue;
300 
301 		if (!tx->update_warp)
302 			continue;
303 
304 		if (r_waterwarpcompute.value)
305 		{
306 			VkImageMemoryBarrier * image_barrier = &warp_image_barriers[num_warp_textures];
307 			image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
308 			image_barrier->pNext = NULL;
309 			image_barrier->srcAccessMask = 0;
310 			image_barrier->dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
311 			image_barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
312 			image_barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
313 			image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
314 			image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
315 			image_barrier->image = tx->warpimage->image;
316 			image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
317 			image_barrier->subresourceRange.baseMipLevel = 0;
318 			image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS;
319 			image_barrier->subresourceRange.baseArrayLayer = 0;
320 			image_barrier->subresourceRange.layerCount = 1;
321 		}
322 
323 		warp_textures[num_warp_textures] = tx;
324 		num_warp_textures += 1;
325 	}
326 
327 	// Transfer mips from UNDEFINED to GENERAL layout
328 	if (r_waterwarpcompute.value)
329 		vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, num_warp_textures, warp_image_barriers);
330 
331 	// Render warp to top mips
332 	for (i = 0; i < num_warp_textures; ++i)
333 	{
334 		tx = warp_textures[i];
335 
336 		if (r_waterwarpcompute.value)
337 			R_ComputeWarpTexture(tx, warptess);
338 		else
339 			R_RasterWarpTexture(tx, warptess);
340 
341 		VkImageMemoryBarrier * image_barrier = &warp_image_barriers[i];
342 		image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
343 		image_barrier->pNext = NULL;
344 		image_barrier->srcAccessMask = 0;
345 		image_barrier->dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
346 		image_barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
347 		image_barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
348 		image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
349 		image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
350 		image_barrier->image = tx->warpimage->image;
351 		image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
352 		image_barrier->subresourceRange.baseMipLevel = 1;
353 		image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS - 1;
354 		image_barrier->subresourceRange.baseArrayLayer = 0;
355 		image_barrier->subresourceRange.layerCount = 1;
356 	}
357 
358 	// Make sure that writes are done for top mips we just rendered to
359 	VkMemoryBarrier memory_barrier;
360 	memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
361 	memory_barrier.pNext = NULL;
362 	memory_barrier.srcAccessMask = r_waterwarpcompute.value ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
363 	memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
364 
365 	// Transfer all other mips from UNDEFINED to GENERAL layout
366 	vkCmdPipelineBarrier(vulkan_globals.command_buffer, r_waterwarpcompute.value ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, NULL, num_warp_textures, warp_image_barriers);
367 
368 	// Generate mip chains
369 	for (mip = 1; mip < WARPIMAGEMIPS; ++mip)
370 	{
371 		int srcSize = WARPIMAGESIZE >> (mip - 1);
372 		int dstSize = WARPIMAGESIZE >> mip;
373 
374 		for (i = 0; i < num_warp_textures; ++i)
375 		{
376 			tx = warp_textures[i];
377 
378 			VkImageBlit region;
379 			memset(&region, 0, sizeof(region));
380 			region.srcOffsets[1].x = srcSize;
381 			region.srcOffsets[1].y = srcSize;
382 			region.srcOffsets[1].z = 1;
383 			region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
384 			region.srcSubresource.layerCount = 1;
385 			region.srcSubresource.mipLevel = (mip - 1);
386 			region.dstOffsets[1].x = dstSize;
387 			region.dstOffsets[1].y = dstSize;
388 			region.dstOffsets[1].z = 1;
389 			region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
390 			region.dstSubresource.layerCount = 1;
391 			region.dstSubresource.mipLevel = mip;
392 
393 			vkCmdBlitImage(vulkan_globals.command_buffer, tx->warpimage->image, VK_IMAGE_LAYOUT_GENERAL, tx->warpimage->image, VK_IMAGE_LAYOUT_GENERAL, 1, &region, VK_FILTER_LINEAR);
394 		}
395 
396 		if (mip < (WARPIMAGEMIPS - 1))
397 		{
398 			memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
399 			memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
400 			vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, NULL, 0, NULL);
401 		}
402 	}
403 
404 	// Transfer all warp texture mips from GENERAL to SHADER_READ_ONLY_OPTIMAL
405 	for (i = 0; i < num_warp_textures; ++i)
406 	{
407 		tx = warp_textures[i];
408 
409 		VkImageMemoryBarrier * image_barrier = &warp_image_barriers[i];
410 		image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
411 		image_barrier->pNext = NULL;
412 		image_barrier->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
413 		image_barrier->dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
414 		image_barrier->oldLayout = VK_IMAGE_LAYOUT_GENERAL;
415 		image_barrier->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
416 		image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
417 		image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
418 		image_barrier->image = tx->warpimage->image;
419 		image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
420 		image_barrier->subresourceRange.baseMipLevel = 0;
421 		image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS;
422 		image_barrier->subresourceRange.baseArrayLayer = 0;
423 		image_barrier->subresourceRange.layerCount = 1;
424 
425 		tx->update_warp = false;
426 	}
427 
428 	vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, num_warp_textures, warp_image_barriers);
429 
430 	//if warp render went down into sbar territory, we need to be sure to refresh it next frame
431 	if (WARPIMAGESIZE + sb_lines > glheight)
432 		Sbar_Changed ();
433 
434 	//if viewsize is less than 100, we need to redraw the frame around the viewport
435 	scr_tileclear_updates = 0;
436 
437 	R_EndDebugUtilsLabel ();
438 }
439