/* TODO: - Firstly save each iteration of our water, so we can keep track of colour etc. - Recalc colour for different dynamic moving lights. */ void Warp_DrawWaterPoly(glpoly_t *p) { VideoObject_t *voWaterPoly; vec3_t vWave,vLightColour; float *v; int i; voWaterPoly = malloc(p->numverts*sizeof(VideoObject_t)); if(!voWaterPoly) { Sys_Error("Failed to allocate water poly!\n"); return; } v = p->verts[0]; for(i = 0; i < p->numverts; i++,v += VERTEXSIZE) { voWaterPoly[i].vTextureCoord[0][0] = WARPCALC(v[3],v[4]); voWaterPoly[i].vTextureCoord[0][1] = WARPCALC(v[4],v[3]); voWaterPoly[i].vColour[3] = Math_Clamp(0, r_wateralpha.value, 1.0f); Math_VectorCopy(v,vWave); // Shitty lit water, use dynamic light points in the future... { MathVector_t mvLightColour; // Use vWave position BEFORE we move it, otherwise the water will flicker. mvLightColour = Light_GetSample(vWave); Math_MVToVector(mvLightColour,vLightColour); Math_VectorScale(vLightColour,1.0f/200.0f,vLightColour); Math_VectorDivide(vLightColour,0.2f,vLightColour); } Math_VectorCopy(vLightColour,voWaterPoly[i].vColour); // [20/1/2013] Added in subtle water bobbing, based on this code http://www.quake-1.com/docs/quakesrc.org/26.html ~hogsy vWave[2] = v[2]+ 2.0f*(float)sin(v[0]*0.025f+cl.time)*(float)sin(v[2]*0.05f+cl.time)+ 2.0f*(float)sin(v[1]*0.025f+cl.time*2.0f)*(float)sin(v[2]*0.05f+cl.time); Math_VectorCopy(vWave,voWaterPoly[i].vVertex); } Video_DrawObject(voWaterPoly,VIDEO_PRIMITIVE_TRIANGLE_FAN,p->numverts); free(voWaterPoly); }
/* Each frame, update warping textures */ void R_UpdateWarpTextures (void) { texture_t *tx; int i; float x, y, x2, warptess; if (r_oldwater.value || cl.bIsPaused || r_drawflat_cheatsafe || r_lightmap_cheatsafe) return; warptess = 128.0f / Math_Clamp(3.0f, floor(r_waterquality.value), 64.0f); for (i=0; i<cl.worldmodel->numtextures; i++) { tx = cl.worldmodel->textures[i]; if(!tx) continue; if(!tx->update_warp) continue; //render warp GL_SetCanvas (CANVAS_WARPIMAGE); Video_SetTexture(tx->gltexture); for (x=0.0; x<128.0; x=x2) { x2 = x + warptess; glBegin (GL_TRIANGLE_STRIP); for (y=0.0; y<128.01; y+=warptess) // .01 for rounding errors { glTexCoord2f (WARPCALC(x,y), WARPCALC(y,x)); glVertex2f (x,y); glTexCoord2f (WARPCALC(x2,y), WARPCALC(y,x2)); glVertex2f (x2,y); } glEnd(); } //copy to texture Video_SetTexture(tx->warpimage); glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, glx, gly+glheight-gl_warpimagesize, gl_warpimagesize, gl_warpimagesize); tx->update_warp = FALSE; } //if viewsize is less than 100, we need to redraw the frame around the viewport scr_tileclear_updates = 0; }
void R_UpdateWarpTextures (void) { texture_t *tx; int i; float x, y, x2, warptess; if (cl.paused || r_drawflat_cheatsafe || r_lightmap_cheatsafe) return; warptess = 128.0/CLAMP (3.0, floor(r_waterquality.value), 64.0); int num_textures = cl.worldmodel->numtextures; int num_warp_textures = 0; // Render warp to top mips for (i = 0; i < num_textures; ++i) { if (!(tx = cl.worldmodel->textures[i])) continue; if (!tx->update_warp) continue; VkRect2D render_area; render_area.offset.x = 0; render_area.offset.y = 0; render_area.extent.width = WARPIMAGESIZE; render_area.extent.height = WARPIMAGESIZE; VkRenderPassBeginInfo render_pass_begin_info; memset(&render_pass_begin_info, 0, sizeof(render_pass_begin_info)); render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderArea = render_area; render_pass_begin_info.renderPass = vulkan_globals.warp_render_pass; render_pass_begin_info.framebuffer = tx->warpimage->frame_buffer; vkCmdBeginRenderPass(vulkan_globals.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); //render warp GL_SetCanvas (CANVAS_WARPIMAGE); vkCmdBindPipeline(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.warp_pipeline); vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_pipeline_layout, 0, 1, &tx->gltexture->descriptor_set, 0, NULL); int num_verts = 0; for (y=0.0; y<128.01; y+=warptess) // .01 for rounding errors num_verts += 2; for (x=0.0; x<128.0; x=x2) { VkBuffer buffer; VkDeviceSize buffer_offset; basicvertex_t * vertices = (basicvertex_t*)R_VertexAllocate(num_verts * sizeof(basicvertex_t), &buffer, &buffer_offset); int i = 0; x2 = x + warptess; for (y=0.0; y<128.01; y+=warptess) // .01 for rounding errors { vertices[i].position[0] = x; vertices[i].position[1] = y; vertices[i].position[2] = 0.0f; vertices[i].texcoord[0] = WARPCALC(x,y); vertices[i].texcoord[1] = WARPCALC(y,x); vertices[i].color[0] = 255; vertices[i].color[1] = 255; vertices[i].color[2] = 255; vertices[i].color[3] = 255; i += 1; vertices[i].position[0] = x2; vertices[i].position[1] = y; vertices[i].position[2] = 0.0f; vertices[i].texcoord[0] = WARPCALC(x2,y); vertices[i].texcoord[1] = WARPCALC(y,x2); vertices[i].color[0] = 255; vertices[i].color[1] = 255; vertices[i].color[2] = 255; vertices[i].color[3] = 255; i += 1; } vkCmdBindVertexBuffers(vulkan_globals.command_buffer, 0, 1, &buffer, &buffer_offset); vkCmdDraw(vulkan_globals.command_buffer, num_verts, 1, 0, 0); } vkCmdEndRenderPass(vulkan_globals.command_buffer); VkImageMemoryBarrier * image_barrier = &warp_image_barriers[num_warp_textures]; image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_barrier->pNext = NULL; image_barrier->srcAccessMask = VK_ACCESS_SHADER_READ_BIT; image_barrier->dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; image_barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_barrier->image = tx->warpimage->image; image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_barrier->subresourceRange.baseMipLevel = 1; image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS - 1; image_barrier->subresourceRange.baseArrayLayer = 0; image_barrier->subresourceRange.layerCount = 1; warp_textures[num_warp_textures] = tx; num_warp_textures += 1; } // Make sure that writes are done for top mips we just rendered to VkMemoryBarrier memory_barrier; memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; memory_barrier.pNext = NULL; memory_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; // Transfer all other mips from UNDEFINED to GENERAL layout vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, NULL, num_warp_textures, warp_image_barriers); // Generate mip chains for (int mip = 1; mip < WARPIMAGEMIPS; ++mip) { int srcSize = WARPIMAGESIZE >> (mip - 1); int dstSize = WARPIMAGESIZE >> mip; for (i = 0; i < num_warp_textures; ++i) { tx = warp_textures[i]; VkImageBlit region; memset(®ion, 0, sizeof(region)); region.srcOffsets[1].x = srcSize; region.srcOffsets[1].y = srcSize; region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.srcSubresource.layerCount = 1; region.srcSubresource.mipLevel = (mip - 1); region.dstOffsets[1].x = dstSize; region.dstOffsets[1].y = dstSize; region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.dstSubresource.layerCount = 1; region.dstSubresource.mipLevel = mip; vkCmdBlitImage(vulkan_globals.command_buffer, tx->warpimage->image, VK_IMAGE_LAYOUT_GENERAL, tx->warpimage->image, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion, VK_FILTER_LINEAR); } if (mip < (WARPIMAGEMIPS - 1)) { memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, NULL, 0, NULL); } } // Transfer all warp texture mips from GENERAL to SHADER_READ_ONLY_OPTIMAL for (i = 0; i < num_warp_textures; ++i) { tx = warp_textures[i]; VkImageMemoryBarrier * image_barrier = &warp_image_barriers[i]; image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_barrier->pNext = NULL; image_barrier->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_barrier->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_barrier->oldLayout = VK_IMAGE_LAYOUT_GENERAL; image_barrier->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_barrier->image = tx->warpimage->image; image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_barrier->subresourceRange.baseMipLevel = 0; image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS; image_barrier->subresourceRange.baseArrayLayer = 0; image_barrier->subresourceRange.layerCount = 1; tx->update_warp = false; } 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); //if warp render went down into sbar territory, we need to be sure to refresh it next frame if (WARPIMAGESIZE + sb_lines > glheight) Sbar_Changed (); //if viewsize is less than 100, we need to redraw the frame around the viewport scr_tileclear_updates = 0; }