[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n/Binaries/\n/Intermediate/\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Vladimir Alyamkin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "Welcome to the VaOcean source code!\n===================================\n\n**Attn.! This branch contains archived version of plugin for UE 4.12 based on [NVIDIA SDK sample](https://developer.nvidia.com/dx11-samples) \"FFT Ocean\". It's deprecated and lives here for history only.**\n\n----------\n\nVaOcean is the ocean surface simulation plugin for [Unreal Engine 4](https://www.unrealengine.com/).\n\nThe plugin includes:\n\n* Component that renders displacement and gradient (normal) maps in real time\n* Sample content, including water shader and grid meshes to be used on scene\n* Set of global shaders that perform FFT calculation and other tech stuff on GPU\n\nCheck the **[Wiki](https://github.com/ufna/VaOcean/wiki)** tab to know more about the plugin.\n\nCurrent version: **0.4 Alpha 6 Hotfix 1**\n\n![SCREENSHOT](SCREENSHOT.jpg)\n\n\nLegal info\n----------\n\nUnreal® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere. Unreal® Engine, Copyright 1998 – 2014, Epic Games, Inc. All rights reserved.\n\n\nReferences\n----------\n\n1. Tessendorf, Jerry. Simulating Ocean Water. In SIGGRAPH 2002 Course Notes #9 (Simulating Nature: Realistic and Interactive Techniques), ACM Press.\n\n1. Phillips, O.M. 1957. On the generation of waves by turbulent wind. Journal of Fluid Mechanics. 2 (5): 417–445.\n\n"
  },
  {
    "path": "Shaders/VaOcean_CS.usf",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"Common.usf\"\n\n#define PI 3.1415926536f\n#define BLOCK_SIZE_X 16\n#define BLOCK_SIZE_Y 16\n\n// Immutable\nuint g_ActualDim;\nuint g_InWidth;\nuint g_OutWidth;\nuint g_OutHeight;\nuint g_DtxAddressOffset;\nuint g_DtyAddressOffset;\n\n// Buffers\nStructuredBuffer<float2>\tg_InputH0;\nStructuredBuffer<float>\t\tg_InputOmega;\nRWStructuredBuffer<float2>\tg_OutputHt;\n\n\n//////////////////////////////////////////////////////////////////////////\n// Pre-FFT data preparation: H(0) -> H(t)\n\n[numthreads(BLOCK_SIZE_X, BLOCK_SIZE_Y, 1)]\nvoid UpdateSpectrumCS(uint3 DTid : SV_DispatchThreadID)\n{\n\tint in_index = DTid.y * g_InWidth + DTid.x;\n\tint in_mindex = (g_ActualDim - DTid.y) * g_InWidth + (g_ActualDim - DTid.x);\n\tint out_index = DTid.y * g_OutWidth + DTid.x;\n\n\t// H(0) -> H(t)\n\tfloat2 h0_k  = g_InputH0[in_index];\n\tfloat2 h0_mk = g_InputH0[in_mindex];\n\tfloat sin_v, cos_v;\n\tsincos(g_InputOmega[in_index] * PerFrameSp.Time, sin_v, cos_v);\n\n\tfloat2 ht;\n\tht.x = (h0_k.x + h0_mk.x) * cos_v - (h0_k.y + h0_mk.y) * sin_v;\n\tht.y = (h0_k.x - h0_mk.x) * sin_v + (h0_k.y - h0_mk.y) * cos_v;\n\n\t// H(t) -> Dx(t), Dy(t)\n\tfloat kx = DTid.x - g_ActualDim * 0.5f;\n\tfloat ky = DTid.y - g_ActualDim * 0.5f;\n\tfloat sqr_k = kx * kx + ky * ky;\n\tfloat rsqr_k = 0;\n\tif (sqr_k > 1e-12f)\n\t{\n\t\trsqr_k = 1 / sqrt(sqr_k);\n\t}\n\t\n\tkx *= rsqr_k;\n\tky *= rsqr_k;\n\tfloat2 dt_x = float2(ht.y * kx, -ht.x * kx);\n\tfloat2 dt_y = float2(ht.y * ky, -ht.x * ky);\n\n\tif ((DTid.x < g_OutWidth) && (DTid.y < g_OutHeight))\n\t{\n\t\tg_OutputHt[out_index] = ht;\n\t\tg_OutputHt[out_index + g_DtxAddressOffset] = dt_x;\n\t\tg_OutputHt[out_index + g_DtyAddressOffset] = dt_y;\n\t}\n}\n"
  },
  {
    "path": "Shaders/VaOcean_FFT.usf",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"Common.usf\"\n\n#define COS_PI_4_16 0.70710678118654752440084436210485f\n#define TWIDDLE_1_8 COS_PI_4_16, -COS_PI_4_16\n#define TWIDDLE_3_8 -COS_PI_4_16, -COS_PI_4_16\n\n#define COHERENCY_GRANULARITY 128\n\n// Source and destination buffers\nStructuredBuffer<float2>\tg_SrcData;\nRWStructuredBuffer<float2>\tg_DstData;\n\n\n//////////////////////////////////////////////////////////////////////////\n// FFT butterfly helper functions\n\nvoid FT2(inout float2 a, inout float2 b)\n{\n\tfloat t;\n\n\tt = a.x;\n\ta.x += b.x;\n\tb.x = t - b.x;\n\n\tt = a.y;\n\ta.y += b.y;\n\tb.y = t - b.y;\n}\n\nvoid CMUL_forward(inout float2 a, float bx, float by)\n{\n\tfloat t = a.x;\n\ta.x = t * bx - a.y * by;\n\ta.y = t * by + a.y * bx;\n}\n\nvoid UPD_forward(inout float2 a, inout float2 b)\n{\n\tfloat A = a.x;\n\tfloat B = b.y;\n\n\ta.x += b.y;\n\tb.y = a.y + b.x;\n\ta.y -= b.x;\n\tb.x = A - B;\n}\n\nvoid FFT_forward_4(inout float2 D[8])\n{\n\tFT2(D[0], D[2]);\n\tFT2(D[1], D[3]);\n\tFT2(D[0], D[1]);\n\n\tUPD_forward(D[2], D[3]);\n}\n\nvoid FFT_forward_8(inout float2 D[8])\n{\n\tFT2(D[0], D[4]);\n\tFT2(D[1], D[5]);\n\tFT2(D[2], D[6]);\n\tFT2(D[3], D[7]);\n\n\tUPD_forward(D[4], D[6]);\n\tUPD_forward(D[5], D[7]);\n\n\tCMUL_forward(D[5], TWIDDLE_1_8);\n\tCMUL_forward(D[7], TWIDDLE_3_8);\n\n\tFFT_forward_4(D);\n\tFT2(D[4], D[5]);\n\tFT2(D[6], D[7]);\n}\n\nvoid TWIDDLE(inout float2 d, float phase)\n{\n\tfloat tx, ty;\n\n\tsincos(phase, ty, tx);\n\tfloat t = d.x;\n\td.x = t * tx - d.y * ty;\n\td.y = t * ty + d.y * tx;\n}\n\nvoid TWIDDLE_8(inout float2 D[8], float phase)\n{\n\tTWIDDLE(D[4], 1 * phase);\n\tTWIDDLE(D[2], 2 * phase);\n\tTWIDDLE(D[6], 3 * phase);\n\tTWIDDLE(D[1], 4 * phase);\n\tTWIDDLE(D[5], 5 * phase);\n\tTWIDDLE(D[3], 6 * phase);\n\tTWIDDLE(D[7], 7 * phase);\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n// Radix FFT compute shaders\n\n[numthreads(COHERENCY_GRANULARITY, 1, 1)]\nvoid Radix008A_CS(uint3 thread_id : SV_DispatchThreadID)\n{\n\tif (thread_id.x >= PerFrameFFT.ThreadCount)\n\t\treturn;\n\n\t// Fetch 8 complex numbers\n\tfloat2 D[8];\n\n\tuint i;\n\tuint imod = thread_id & (PerFrameFFT.istride - 1);\n\tuint iaddr = ((thread_id - imod) << 3) + imod;\n\tfor (i = 0; i < 8; i++)\n\t{\n\t\tD[i] = g_SrcData[iaddr + i * PerFrameFFT.istride];\n\t}\n\n\t// Math\n\tFFT_forward_8(D);\n\tuint p = thread_id & (PerFrameFFT.istride - PerFrameFFT.pstride);\n\tfloat phase = PerFrameFFT.PhaseBase * (float)p;\n\tTWIDDLE_8(D, phase);\n\n\t// Store the result\n\tuint omod = thread_id & (PerFrameFFT.ostride - 1);\n\tuint oaddr = ((thread_id - omod) << 3) + omod;\n\tg_DstData[oaddr + 0 * PerFrameFFT.ostride] = D[0];\n\tg_DstData[oaddr + 1 * PerFrameFFT.ostride] = D[4];\n\tg_DstData[oaddr + 2 * PerFrameFFT.ostride] = D[2];\n\tg_DstData[oaddr + 3 * PerFrameFFT.ostride] = D[6];\n\tg_DstData[oaddr + 4 * PerFrameFFT.ostride] = D[1];\n\tg_DstData[oaddr + 5 * PerFrameFFT.ostride] = D[5];\n\tg_DstData[oaddr + 6 * PerFrameFFT.ostride] = D[3];\n\tg_DstData[oaddr + 7 * PerFrameFFT.ostride] = D[7];\n}\n\n[numthreads(COHERENCY_GRANULARITY, 1, 1)]\nvoid Radix008A_CS2(uint3 thread_id : SV_DispatchThreadID)\n{\n\tif(thread_id.x >= PerFrameFFT.ThreadCount)\n\t\treturn;\n\n\t// Fetch 8 complex numbers\n\tuint i;\n\tfloat2 D[8];\n\tuint iaddr = thread_id << 3;\n\tfor (i = 0; i < 8; i++)\n\t{\n\t\tD[i] = g_SrcData[iaddr + i];\n\t}\n\n\t// Math\n\tFFT_forward_8(D);\n\n\t// Store the result\n\tuint omod = thread_id & (PerFrameFFT.ostride - 1);\n\tuint oaddr = ((thread_id - omod) << 3) + omod;\n\tg_DstData[oaddr + 0 * PerFrameFFT.ostride] = D[0];\n\tg_DstData[oaddr + 1 * PerFrameFFT.ostride] = D[4];\n\tg_DstData[oaddr + 2 * PerFrameFFT.ostride] = D[2];\n\tg_DstData[oaddr + 3 * PerFrameFFT.ostride] = D[6];\n\tg_DstData[oaddr + 4 * PerFrameFFT.ostride] = D[1];\n\tg_DstData[oaddr + 5 * PerFrameFFT.ostride] = D[5];\n\tg_DstData[oaddr + 6 * PerFrameFFT.ostride] = D[3];\n\tg_DstData[oaddr + 7 * PerFrameFFT.ostride] = D[7];\n}\n"
  },
  {
    "path": "Shaders/VaOcean_VS_PS.usf",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"Common.usf\"\n\n\n//////////////////////////////////////////////////////////////////////////\n// Vertex shaders\n\nvoid QuadVS(\n\tin float4 InPosition : ATTRIBUTE0,\n\tin float2 InTexCoord : ATTRIBUTE1,\n\tout float2 OutTexCoord : TEXCOORD0,\n\tout float4 OutPosition : SV_POSITION)\n{\n\tOutPosition = InPosition;\n\tOutTexCoord.x = 0.5f + InPosition.x * 0.5f;\n\tOutTexCoord.y = 0.5f - InPosition.y * 0.5f;\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n// Pixel shaders\n\n// Immutable\nuint g_ActualDim;\nuint g_InWidth;\nuint g_OutWidth;\nuint g_OutHeight;\nuint g_DtxAddressOffset;\nuint g_DtyAddressOffset;\n\n// The following three should contains only real numbers. But we have only C2C FFT now.\nStructuredBuffer<float2> g_InputDxyz;\n\n// Post-FFT data wrap up: Dx, Dy, Dz -> Displacement\nvoid UpdateDisplacementPS(float2 UV : TEXCOORD0, out float4 OutColor : SV_Target0)\n{\n\tuint index_x = (uint)(UV.x * (float)g_OutWidth);\n\tuint index_y = (uint)(UV.y * (float)g_OutHeight);\n\tuint addr = g_OutWidth * index_y + index_x;\n\n\t// cos(pi * (m1 + m2))\n\tint sign_correction = ((index_x + index_y) & 1) ? -1 : 1;\n\n\tfloat dx = g_InputDxyz[addr + g_DtxAddressOffset].x * sign_correction * PerFrameDisp.ChoppyScale;\n\tfloat dy = g_InputDxyz[addr + g_DtyAddressOffset].x * sign_correction * PerFrameDisp.ChoppyScale;\n\tfloat dz = g_InputDxyz[addr].x * sign_correction;\n\n\tOutColor = float4(dx, dy, dz, 1);\n}\n\n\n// Textures and sampling states\nTexture2D \t\tDisplacementMap;\nSamplerState \tDisplacementMapSampler;\n\n// Displacement -> Normal, Folding\nvoid GenGradientFoldingPS(float2 UV : TEXCOORD0, out float4 OutColor : SV_Target0)\n{\n\t// Sample neighbour texels\n\tfloat2 one_texel = float2(1.0f / (float)g_OutWidth, 1.0f / (float)g_OutHeight);\n\n\tfloat2 tc_left  = float2(UV.x - one_texel.x, UV.y);\n\tfloat2 tc_right = float2(UV.x + one_texel.x, UV.y);\n\tfloat2 tc_back  = float2(UV.x, UV.y - one_texel.y);\n\tfloat2 tc_front = float2(UV.x, UV.y + one_texel.y);\n\n\tfloat3 displace_left  = DisplacementMap.Sample(DisplacementMapSampler, tc_left).xyz;\n\tfloat3 displace_right = DisplacementMap.Sample(DisplacementMapSampler, tc_right).xyz;\n\tfloat3 displace_back  = DisplacementMap.Sample(DisplacementMapSampler, tc_back).xyz;\n\tfloat3 displace_front = DisplacementMap.Sample(DisplacementMapSampler, tc_front).xyz;\n\t\n\t// Do not store the actual normal value. Using gradient instead, which preserves two differential values.\n\tfloat2 gradient = {-(displace_right.z - displace_left.z), -(displace_front.z - displace_back.z)};\n\t\n\n\t// Calculate Jacobian corelation from the partial differential of height field\n\tfloat2 Dx = (displace_right.xy - displace_left.xy) * PerFrameDisp.ChoppyScale * PerFrameDisp.GridLen;\n\tfloat2 Dy = (displace_front.xy - displace_back.xy) * PerFrameDisp.ChoppyScale * PerFrameDisp.GridLen;\n\tfloat J = (1.0f + Dx.x) * (1.0f + Dy.y) - Dx.y * Dy.x;\n\n\t// Practical subsurface scale calculation: max[0, (1 - J) + Amplitude * (2 * Coverage - 1)].\n\tfloat fold = max(1.0f - J, 0);\n\n\t// Output\n\tOutColor = float4(gradient, 0, fold);\n}\n"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanRadixFFT.h",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanPluginPrivatePCH.h\"\n#include \"VaOceanRadixFFT.generated.h\"\n\n/** Memory access coherency (in threads) */\n#define COHERENCY_GRANULARITY 128\n\n/** Common constants */\n#define TWO_PI 6.283185307179586476925286766559\n\n#define FFT_DIMENSIONS 3U\n#define FFT_PLAN_SIZE_LIMIT (1U << 27)\n\n#define FFT_FORWARD -1\n#define FFT_INVERSE 1\n\n#define FFT_PARAM_SETS 6\n\n/** Per frame parameters for FRadix008A_CS shader */\nUSTRUCT()\nstruct FRadix008A_CSPerFrame\n{\n\tGENERATED_USTRUCT_BODY()\n\n\tuint32 ThreadCount;\n\tuint32 ostride;\n\tuint32 istride;\n\tuint32 pstride;\n\tfloat PhaseBase;\n};\n\n/** Radix FFT data (for 512x512 buffer size) */\nUSTRUCT()\nstruct FRadixPlan512\n{\n\tGENERATED_USTRUCT_BODY()\n\n\t// More than one array can be transformed at same time\n\tuint32 Slices;\n\n\t// For 512x512 config, we need 6 sets of parameters\n\tFRadix008A_CSPerFrame PerFrame[FFT_PARAM_SETS];\n\n\t// Temporary buffers\n\tFStructuredBufferRHIRef pBuffer_Tmp;\n\tFUnorderedAccessViewRHIRef pUAV_Tmp;\n\tFShaderResourceViewRHIRef pSRV_Tmp;\n};\n\n\nvoid RadixCreatePlan(FRadixPlan512* Plan, uint32 Slices);\nvoid RadixDestroyPlan(FRadixPlan512* Plan);\n\nvoid RadixCompute(\tFRHICommandListImmediate& RHICmdList,\n\t\t\t\t\tFRadixPlan512* Plan,\n\t\t\t\t\tFUnorderedAccessViewRHIRef pUAV_Dst,\n\t\t\t\t\tFShaderResourceViewRHIRef pSRV_Dst, \n\t\t\t\t\tFShaderResourceViewRHIRef pSRV_Src);\n"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanShaders.h",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanPluginPrivatePCH.h\"\n#include \"VaOceanShaders.generated.h\"\n\n#define HALF_SQRT_2\t0.7071068f\n#define GRAV_ACCEL\t981.0f\t// The acceleration of gravity, cm/s^2\n\n#define BLOCK_SIZE_X 16\n#define BLOCK_SIZE_Y 16\n\n\n//////////////////////////////////////////////////////////////////////////\n// UpdateSpectrumCS compute shader\n\nBEGIN_UNIFORM_BUFFER_STRUCT(FUpdateSpectrumUniformParameters, )\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, Time)\nEND_UNIFORM_BUFFER_STRUCT(FUpdateSpectrumUniformParameters)\n\ntypedef TUniformBufferRef<FUpdateSpectrumUniformParameters> FUpdateSpectrumUniformBufferRef;\n\n/** Immutable parameters for UpdateSpectrumCS shader*/\nUSTRUCT()\nstruct FUpdateSpectrumCSImmutable\n{\n\tGENERATED_USTRUCT_BODY()\n\n\tuint32 g_ActualDim;\n\tuint32 g_InWidth;\n\tuint32 g_OutWidth;\n\tuint32 g_OutHeight;\n\tuint32 g_DtxAddressOffset;\n\tuint32 g_DtyAddressOffset;\n};\n\n/** Per frame parameters for UpdateSpectrumCS shader */\nUSTRUCT()\nstruct FUpdateSpectrumCSPerFrame\n{\n\tGENERATED_USTRUCT_BODY()\n\n\tFShaderResourceViewRHIRef m_pSRV_H0;\n\tFShaderResourceViewRHIRef m_pSRV_Omega;\n\tFUnorderedAccessViewRHIRef m_pUAV_Ht;\n\n\t// Used to pass params into render thread\n\tfloat g_Time;\n\tfloat g_ChoppyScale;\n};\n\n/**\n * H(0) -> H(t), D(x,t), D(y,t)\n */\nclass FUpdateSpectrumCS : public FGlobalShader\n{\n\tDECLARE_SHADER_TYPE(FUpdateSpectrumCS, Global)\n\npublic:\n\tstatic bool ShouldCache(EShaderPlatform Platform)\n\t{\n\t\treturn IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);\n\t}\n\n\tFUpdateSpectrumCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)\n\t\t: FGlobalShader(Initializer)\n\t{\n\t\tActualDim.Bind(Initializer.ParameterMap, TEXT(\"g_ActualDim\"), SPF_Mandatory);\n\t\tInWidth.Bind(Initializer.ParameterMap, TEXT(\"g_InWidth\"), SPF_Mandatory);\n\t\tOutWidth.Bind(Initializer.ParameterMap, TEXT(\"g_OutWidth\"), SPF_Mandatory);\n\t\tOutHeight.Bind(Initializer.ParameterMap, TEXT(\"g_OutHeight\"), SPF_Mandatory);\n\t\tDtxAddressOffset.Bind(Initializer.ParameterMap, TEXT(\"g_DtxAddressOffset\"), SPF_Mandatory);\n\t\tDtyAddressOffset.Bind(Initializer.ParameterMap, TEXT(\"g_DtyAddressOffset\"), SPF_Mandatory);\n\n\t\tInputH0.Bind(Initializer.ParameterMap, TEXT(\"g_InputH0\"), SPF_Mandatory);\n\t\tInputOmega.Bind(Initializer.ParameterMap, TEXT(\"g_InputOmega\"), SPF_Mandatory);\n\n\t\tOutputHtRW.Bind(Initializer.ParameterMap, TEXT(\"g_OutputHt\"), SPF_Mandatory);\n\t}\n\n\tFUpdateSpectrumCS()\n\t{\n\t}\n\n\tvoid SetParameters(\n\t\tFRHICommandList& RHICmdList,\n\t\tuint32 ParamActualDim,\n\t\tuint32 ParamInWidth,\n\t\tuint32 ParamOutWidth,\n\t\tuint32 ParamOutHeight,\n\t\tuint32 ParamDtxAddressOffset,\n\t\tuint32 ParamDtyAddressOffset\n\t\t)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\n\t\tSetShaderValue(RHICmdList, ComputeShaderRHI, ActualDim, ParamActualDim);\n\t\tSetShaderValue(RHICmdList, ComputeShaderRHI, InWidth, ParamInWidth);\n\t\tSetShaderValue(RHICmdList, ComputeShaderRHI, OutWidth, ParamOutWidth);\n\t\tSetShaderValue(RHICmdList, ComputeShaderRHI, OutHeight, ParamOutHeight);\n\t\tSetShaderValue(RHICmdList, ComputeShaderRHI, DtxAddressOffset, ParamDtxAddressOffset);\n\t\tSetShaderValue(RHICmdList, ComputeShaderRHI, DtyAddressOffset, ParamDtyAddressOffset);\n\t}\n\n\tvoid SetParameters(\n\t\tFRHICommandList& RHICmdList,\n\t\tconst FUpdateSpectrumUniformBufferRef& UniformBuffer,\n\t\tFShaderResourceViewRHIRef ParamInputH0,\n\t\tFShaderResourceViewRHIRef ParamInputOmega\n\t\t)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\n\t\tSetUniformBufferParameter(RHICmdList, ComputeShaderRHI, GetUniformBufferParameter<FUpdateSpectrumUniformParameters>(), UniformBuffer);\n\n\t\tRHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputH0.GetBaseIndex(), ParamInputH0);\n\t\tRHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputOmega.GetBaseIndex(), ParamInputOmega);\n\t}\n\n\tvoid UnsetParameters(FRHICommandList &RHICmdList)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\t\tFShaderResourceViewRHIParamRef NullSRV = FShaderResourceViewRHIParamRef();\n\n\t\tRHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputH0.GetBaseIndex(), NullSRV);\n\t\tRHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputOmega.GetBaseIndex(), NullSRV);\n\t}\n\n\tvoid SetOutput(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef ParamOutputHtRW)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\t\tif (OutputHtRW.IsBound())\n\t\t{\n\t\t\tRHICmdList.SetUAVParameter(ComputeShaderRHI, OutputHtRW.GetBaseIndex(), ParamOutputHtRW);\n\t\t}\n\t}\n\n\tvoid UnbindBuffers(FRHICommandList& RHICmdList)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\t\tif (OutputHtRW.IsBound())\n\t\t{\n\t\t\tRHICmdList.SetUAVParameter(ComputeShaderRHI, OutputHtRW.GetBaseIndex(), FUnorderedAccessViewRHIParamRef());\n\t\t}\n\t}\n\n\tvirtual bool Serialize(FArchive& Ar)\n\t{\n\t\tbool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);\n\t\tAr << ActualDim << InWidth << OutWidth << OutHeight << DtxAddressOffset << DtyAddressOffset\n\t\t\t<< InputH0 << InputOmega << OutputHtRW;\n\n\t\treturn bShaderHasOutdatedParameters;\n\t}\n\nprivate:\n\t// Immutable\n\tFShaderParameter ActualDim;\n\tFShaderParameter InWidth;\n\tFShaderParameter OutWidth;\n\tFShaderParameter OutHeight;\n\tFShaderParameter DtxAddressOffset;\n\tFShaderParameter DtyAddressOffset;\n\n\t// Buffers\n\tFShaderResourceParameter InputH0;\n\tFShaderResourceParameter InputOmega;\n\tFShaderResourceParameter OutputHtRW;\n\n};\n\n\n//////////////////////////////////////////////////////////////////////////\n// Radix008A_CS compute shader\n\nBEGIN_UNIFORM_BUFFER_STRUCT(FRadixFFTUniformParameters, )\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, ThreadCount)\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, ostride)\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, istride)\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, pstride)\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, PhaseBase)\nEND_UNIFORM_BUFFER_STRUCT(FRadixFFTUniformParameters)\n\ntypedef TUniformBufferRef<FRadixFFTUniformParameters> FRadixFFTUniformBufferRef;\n\n/**\n * FFT calculations for istride > 1 \n */\nclass FRadix008A_CS : public FGlobalShader\n{\n\tDECLARE_SHADER_TYPE(FRadix008A_CS, Global)\n\npublic:\n\tstatic bool ShouldCache(EShaderPlatform Platform)\n\t{\n\t\treturn IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);\n\t}\n\n\tFRadix008A_CS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)\n\t\t: FGlobalShader(Initializer)\n\t{\n\t\tSrcData.Bind(Initializer.ParameterMap, TEXT(\"g_SrcData\"));\n\t\tDstData.Bind(Initializer.ParameterMap, TEXT(\"g_DstData\"));\n\t}\n\n\tFRadix008A_CS()\n\t{\n\t}\n\n\tvoid SetParameters(FRHICommandList& RHICmdList, const FRadixFFTUniformBufferRef& UniformBuffer)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\n\t\tSetUniformBufferParameter(RHICmdList, ComputeShaderRHI, GetUniformBufferParameter<FRadixFFTUniformParameters>(), UniformBuffer);\n\t}\n\n\tvoid SetParameters(FRHICommandList& RHICmdList, FShaderResourceViewRHIRef ParamSrcData, FUnorderedAccessViewRHIRef ParamDstData)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\n\t\tRHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, SrcData.GetBaseIndex(), ParamSrcData);\n\t\tRHICmdList.SetUAVParameter(ComputeShaderRHI, DstData.GetBaseIndex(), ParamDstData);\n\t}\n\n\tvoid UnsetParameters(FRHICommandList& RHICmdList)\n\t{\n\t\tFComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();\n\n\t\tRHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, SrcData.GetBaseIndex(), FShaderResourceViewRHIParamRef());\n\t\tRHICmdList.SetUAVParameter(ComputeShaderRHI, DstData.GetBaseIndex(), FUnorderedAccessViewRHIParamRef());\n\t}\n\n\tvirtual bool Serialize(FArchive& Ar)\n\t{\n\t\tbool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);\n\t\tAr << SrcData << DstData;\n\n\t\treturn bShaderHasOutdatedParameters;\n\t}\n\nprivate:\n\t// Buffers\n\tFShaderResourceParameter SrcData;\n\tFShaderResourceParameter DstData;\n\n};\n\n/**\n * pstride and istride parameters are excess here, but we use inheritance as its easier for now\n */\nclass FRadix008A_CS2 : public FRadix008A_CS\n{\n\tDECLARE_SHADER_TYPE(FRadix008A_CS2, Global)\n\npublic:\n\tFRadix008A_CS2(const ShaderMetaType::CompiledShaderInitializerType& Initializer)\n\t\t: FRadix008A_CS(Initializer)\n\t{\n\t}\n\n\tFRadix008A_CS2()\n\t{\n\t}\n};\n\n\n//////////////////////////////////////////////////////////////////////////\n// Simple Quad vertex shader\n\n/** The vertex data used to render displacement */\nstruct FQuadVertex\n{\n\tFVector4 Position;\n\tFVector2D UV;\n};\n\n/** The displacement vertex declaration resource type */\nclass FQuadVertexDeclaration : public FRenderResource\n{\npublic:\n\tFVertexDeclarationRHIRef VertexDeclarationRHI;\n\n\t/** Destructor */\n\tvirtual ~FQuadVertexDeclaration() {}\n\n\tvirtual void InitRHI()\n\t{\n\t\tFVertexDeclarationElementList Elements;\n\t\tElements.Add(FVertexElement(0, STRUCT_OFFSET(FQuadVertex, Position), VET_Float4, 0, sizeof(FQuadVertex)));\n\t\tElements.Add(FVertexElement(0, STRUCT_OFFSET(FQuadVertex, UV), VET_Float2, 1, sizeof(FQuadVertex)));\n\t\tVertexDeclarationRHI = RHICreateVertexDeclaration(Elements);\n\t}\n\n\tvirtual void ReleaseRHI()\n\t{\n\t\tVertexDeclarationRHI.SafeRelease();\n\t}\n};\n\nclass FQuadVS : public FGlobalShader\n{\n\tDECLARE_SHADER_TYPE(FQuadVS, Global);\n\npublic:\n\tstatic bool ShouldCache(EShaderPlatform Platform)\n\t{\n\t\treturn true;\n\t}\n\n\tFQuadVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)\n\t\t: FGlobalShader(Initializer)\n\t{\n\t}\n\n\tFQuadVS() {}\n};\n\n\n//////////////////////////////////////////////////////////////////////////\n// Post-FFT data wrap up: Dx, Dy, Dz -> Displacement\n\nBEGIN_UNIFORM_BUFFER_STRUCT(FUpdateDisplacementUniformParameters, )\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, ChoppyScale)\n\tDECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, GridLen)\nEND_UNIFORM_BUFFER_STRUCT(FUpdateDisplacementUniformParameters)\n\ntypedef TUniformBufferRef<FUpdateDisplacementUniformParameters> FUpdateDisplacementUniformBufferRef;\n\n/** Per frame parameters for UpdateDisplacementPS shader */\nUSTRUCT()\nstruct FUpdateDisplacementPSPerFrame\n{\n\tGENERATED_USTRUCT_BODY()\n\n\tFVector4 m_pQuadVB[4];\n\n\tFShaderResourceViewRHIRef g_InputDxyz;\n\n\t// Used to pass params into render thread\n\tfloat g_ChoppyScale;\n\tfloat g_GridLen;\n};\n\n/**\n * Post-FFT data wrap up: Dx, Dy, Dz -> Displacement\n */\nclass FUpdateDisplacementPS : public FGlobalShader\n{\n\tDECLARE_SHADER_TYPE(FUpdateDisplacementPS, Global)\n\npublic:\n\tstatic bool ShouldCache(EShaderPlatform Platform)\n\t{\n\t\treturn IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);\n\t}\n\n\tFUpdateDisplacementPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)\n\t\t: FGlobalShader(Initializer)\n\t{\n\t\tActualDim.Bind(Initializer.ParameterMap, TEXT(\"g_ActualDim\"));\n\t\tInWidth.Bind(Initializer.ParameterMap, TEXT(\"g_InWidth\"));\n\t\tOutWidth.Bind(Initializer.ParameterMap, TEXT(\"g_OutWidth\"));\n\t\tOutHeight.Bind(Initializer.ParameterMap, TEXT(\"g_OutHeight\"));\n\t\tDtxAddressOffset.Bind(Initializer.ParameterMap, TEXT(\"g_DtxAddressOffset\"));\n\t\tDtyAddressOffset.Bind(Initializer.ParameterMap, TEXT(\"g_DtyAddressOffset\"));\n\n\t\tInputDxyz.Bind(Initializer.ParameterMap, TEXT(\"g_InputDxyz\"));\n\t}\n\n\tFUpdateDisplacementPS()\n\t{\n\t}\n\n\tvoid SetParameters(\n\t\tFRHICommandList& RHICmdList,\n\t\tuint32 ParamActualDim,\n\t\tuint32 ParamInWidth,\n\t\tuint32 ParamOutWidth,\n\t\tuint32 ParamOutHeight,\n\t\tuint32 ParamDtxAddressOffset,\n\t\tuint32 ParamDtyAddressOffset\n\t\t)\n\t{\n\t\tFPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();\n\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, ActualDim, ParamActualDim);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, InWidth, ParamInWidth);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, OutWidth, ParamOutWidth);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, OutHeight, ParamOutHeight);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, DtxAddressOffset, ParamDtxAddressOffset);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, DtyAddressOffset, ParamDtyAddressOffset);\n\t}\n\n\tvoid SetParameters(\n\t\tFRHICommandList& RHICmdList,\n\t\tconst FUpdateDisplacementUniformBufferRef& UniformBuffer,\n\t\tFShaderResourceViewRHIRef ParamInputDxyz\n\t\t)\n\t{\n\t\tFPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();\n\n\t\tSetUniformBufferParameter(RHICmdList, PixelShaderRHI, GetUniformBufferParameter<FUpdateDisplacementUniformParameters>(), UniformBuffer);\n\n\t\tRHICmdList.SetShaderResourceViewParameter(PixelShaderRHI, InputDxyz.GetBaseIndex(), ParamInputDxyz);\n\t}\n\n\tvoid UnsetParameters(FRHICommandList& RHICmdList)\n\t{\n\t\tFPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();\n\n\t\tRHICmdList.SetShaderResourceViewParameter(PixelShaderRHI, InputDxyz.GetBaseIndex(), FShaderResourceViewRHIParamRef());\n\t}\n\n\tvirtual bool Serialize(FArchive& Ar)\n\t{\n\t\tbool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);\n\t\tAr << ActualDim << InWidth << OutWidth << OutHeight << DtxAddressOffset << DtyAddressOffset << InputDxyz;\n\n\t\treturn bShaderHasOutdatedParameters;\n\t}\n\nprivate:\n\t// Immutable\n\tFShaderParameter ActualDim;\n\tFShaderParameter InWidth;\n\tFShaderParameter OutWidth;\n\tFShaderParameter OutHeight;\n\tFShaderParameter DtxAddressOffset;\n\tFShaderParameter DtyAddressOffset;\n\n\t// Buffers\n\tFShaderResourceParameter InputDxyz;\n\n};\n\n\n//////////////////////////////////////////////////////////////////////////\n// Generate Normal\n\n/** Per frame parameters for UpdateDisplacementPS shader */\nUSTRUCT()\nstruct FGenGradientFoldingPSPerFrame\n{\n\tGENERATED_USTRUCT_BODY()\n\n\tFVector4 m_pQuadVB[4];\n\n\t// Used to pass params into render thread\n\tfloat g_ChoppyScale;\n\tfloat g_GridLen;\n};\n\n/**\n * Displacement -> Normal, Folding\n */\nclass FGenGradientFoldingPS : public FGlobalShader\n{\n\tDECLARE_SHADER_TYPE(FGenGradientFoldingPS, Global)\n\npublic:\n\tstatic bool ShouldCache(EShaderPlatform Platform)\n\t{\n\t\treturn IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);\n\t}\n\n\tFGenGradientFoldingPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)\n\t\t: FGlobalShader(Initializer)\n\t{\n\t\tActualDim.Bind(Initializer.ParameterMap, TEXT(\"g_ActualDim\"));\n\t\tInWidth.Bind(Initializer.ParameterMap, TEXT(\"g_InWidth\"));\n\t\tOutWidth.Bind(Initializer.ParameterMap, TEXT(\"g_OutWidth\"));\n\t\tOutHeight.Bind(Initializer.ParameterMap, TEXT(\"g_OutHeight\"));\n\t\tDtxAddressOffset.Bind(Initializer.ParameterMap, TEXT(\"g_DtxAddressOffset\"));\n\t\tDtyAddressOffset.Bind(Initializer.ParameterMap, TEXT(\"g_DtyAddressOffset\"));\n\n\t\tDisplacementMap.Bind(Initializer.ParameterMap, TEXT(\"DisplacementMap\"));\n\t\tDisplacementMapSampler.Bind(Initializer.ParameterMap, TEXT(\"DisplacementMapSampler\"));\n\t}\n\n\tFGenGradientFoldingPS()\n\t{\n\t}\n\n\tvoid SetParameters(\n\t\tFRHICommandList& RHICmdList,\n\t\tuint32 ParamActualDim,\n\t\tuint32 ParamInWidth,\n\t\tuint32 ParamOutWidth,\n\t\tuint32 ParamOutHeight,\n\t\tuint32 ParamDtxAddressOffset,\n\t\tuint32 ParamDtyAddressOffset\n\t\t)\n\t{\n\t\tFPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();\n\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, ActualDim, ParamActualDim);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, InWidth, ParamInWidth);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, OutWidth, ParamOutWidth);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, OutHeight, ParamOutHeight);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, DtxAddressOffset, ParamDtxAddressOffset);\n\t\tSetShaderValue(RHICmdList, PixelShaderRHI, DtyAddressOffset, ParamDtyAddressOffset);\n\t}\n\n\tvoid SetParameters(\n\t\tFRHICommandList& RHICmdList,\n\t\tconst FUpdateDisplacementUniformBufferRef& UniformBuffer,\n\t\tFTextureRHIParamRef DisplacementMapRHI\n\t\t)\n\t{\n\t\tFPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();\n\n\t\tSetUniformBufferParameter(RHICmdList, PixelShaderRHI, GetUniformBufferParameter<FUpdateDisplacementUniformParameters>(), UniformBuffer);\n\n\t\tFSamplerStateRHIParamRef SamplerStateLinear = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();\n\t\tSetTextureParameter(RHICmdList, PixelShaderRHI, DisplacementMap, DisplacementMapSampler, SamplerStateLinear, DisplacementMapRHI);\n\t}\n\n\tvoid UnsetParameters(FRHICommandList& RHICmdList) {}\n\n\tvirtual bool Serialize(FArchive& Ar)\n\t{\n\t\tbool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);\n\t\tAr << ActualDim << InWidth << OutWidth << OutHeight << DtxAddressOffset << DtyAddressOffset\n\t\t\t<< DisplacementMap << DisplacementMapSampler;\n\n\t\treturn bShaderHasOutdatedParameters;\n\t}\n\nprivate:\n\t// Immutable\n\tFShaderParameter ActualDim;\n\tFShaderParameter InWidth;\n\tFShaderParameter OutWidth;\n\tFShaderParameter OutHeight;\n\tFShaderParameter DtxAddressOffset;\n\tFShaderParameter DtyAddressOffset;\n\n\t// Displacement map\n\tFShaderResourceParameter DisplacementMap;\n\tFShaderResourceParameter DisplacementMapSampler;\n\n};\n\n"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanSimulator.h",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanTypes.h\"\n#include \"VaOceanPluginPrivatePCH.h\"\n\n#include \"VaOceanSimulator.generated.h\"\n\n#define PAD16(n) (((n)+15)/16*16)\n\n/**\n * Renders normals and heightmap from Phillips spectrum\n */\nUCLASS(Blueprintable, BlueprintType, ClassGroup=Environment)\nclass VAOCEANPLUGIN_API AVaOceanSimulator : public AActor\n{\n\tGENERATED_UCLASS_BODY()\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Initialization\n\nprotected:\n\t/** Initialize all buffers and prepare shaders */\n\tvoid InitializeInternalData();\n\n\t/** Initialize the vector field */\n\tvoid InitHeightMap(const FSpectrumData& Params, TResourceArray<FVector2D>& out_h0, TResourceArray<float>& out_omega);\n\n\t/** Initialize buffers for shader */\n\tvoid CreateBufferAndUAV(FResourceArrayInterface* Data, uint32 byte_width, uint32 byte_stride, FStructuredBufferRHIRef* ppBuffer, FUnorderedAccessViewRHIRef* ppUAV, FShaderResourceViewRHIRef* ppSRV);\n\n\t/** Clear internal buffers and shader data */\n\tvoid ClearInternalData();\n\n\t/** Clear buffers and re-initalize them */\n\tvoid ResetInternalData();\n\n\t// Begin UObject Interface\n\tvirtual void BeginDestroy() override;\n\n#if WITH_EDITOR\n\tvirtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;\n#endif // WITH_EDITOR\n\t// End UObject Interface\n\n\t/** Allow tick in editor */\n\tvirtual bool ShouldTickIfViewportsOnly() const override;\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Simulation\n\npublic:\n\t/** Update ocean simulation */\n\tvirtual void Tick(float DeltaSeconds) override;\n\nprotected:\n\t/** Update normals and heightmap from spectrum */\n\tvoid UpdateDisplacementMap(float WorldTime);\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Spectrum configuration\n\npublic:\n\t/** Get spectrum config */\n\tUFUNCTION(BlueprintCallable, Category = \"VaOcean|FFT\")\n\tconst FSpectrumData& GetSpectrumConfig() const;\n\nprotected:\n\t/** Ocean spectrum data */\n\tUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Config)\n\tFSpectrumData SpectrumConfig;\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Shader output targets\n\npublic:\n\t/** Render target for normal map that can be used by the editor */\n\tUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Config)\n\tUTextureRenderTarget2D* DisplacementTexture;\n\n\t/** Render target for height map that can be used by the editor */\n\tUPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Config)\n\tUTextureRenderTarget2D* GradientTexture;\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Parameters that will be send to rendering thread\n\nprotected:\n\tFUpdateSpectrumCSImmutable UpdateSpectrumCSImmutableParams;\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Spectrum simulation data\n\nprotected:\n\t/** Initial height field H(0) generated by Phillips spectrum & Gauss distribution. */\n\tFStructuredBufferRHIRef m_pBuffer_Float2_H0;\n\tFUnorderedAccessViewRHIRef m_pUAV_H0;\n\tFShaderResourceViewRHIRef m_pSRV_H0;\n\n\t/** Angular frequency */\n\tFStructuredBufferRHIRef m_pBuffer_Float_Omega;\n\tFUnorderedAccessViewRHIRef m_pUAV_Omega;\n\tFShaderResourceViewRHIRef m_pSRV_Omega;\n\n\t/** Height field H(t), choppy field Dx(t) and Dy(t) in frequency domain, updated each frame. */\n\tFStructuredBufferRHIRef m_pBuffer_Float2_Ht;\n\tFUnorderedAccessViewRHIRef m_pUAV_Ht;\n\tFShaderResourceViewRHIRef m_pSRV_Ht;\n\n\t/** Height & choppy buffer in the space domain, corresponding to H(t), Dx(t) and Dy(t) */\n\tFStructuredBufferRHIRef m_pBuffer_Float_Dxyz;\n\tFUnorderedAccessViewRHIRef m_pUAV_Dxyz;\n\tFShaderResourceViewRHIRef m_pSRV_Dxyz;\n\n\tFVector4 m_pQuadVB[4];\n\n\t/** FFT wrap-up */\n\tFRadixPlan512 FFTPlan;\n\n\t/** Initialization flags */\n\tbool bSimulatorInitializated;\n\n\t/** Internal world simulation time */\n\tfloat SimulationWorldTime;\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Utilities\n\npublic:\n\t/**\n\t * Creates a new RenderTarget with desired params\n\t *\n\t * @param bInForceLinearGamma\tWhether or not to force linear gamma\n\t * @param InPixelFormat\t\t\tPixel format of the render target\n\t * @param InTargetSize\t\t\tDimensions of the render target\n\t * @return\t\t\t\t\t\tCreated render target\n\t */\n\tUTextureRenderTarget2D* CreateRenderTarget(bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint& InTargetSize);\n\n\t/**\n\t * SetupsRenderTarget with desired params\n\t *\n\t * @param bInForceLinearGamma\tWhether or not to force linear gamma\n\t * @param InPixelFormat\t\t\tPixel format of the render target\n\t * @param InTargetSize\t\t\tDimensions of the render target\n\t * @return\t\t\t\t\t\tCreated render target\n\t */\n\tstatic void SetupRenderTarget(UTextureRenderTarget2D* InRenderTarget, bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint& InTargetSize);\n\n};\n"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanTypes.h",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanTypes.generated.h\"\n\n/** Phillips spectrum configuration */\nUSTRUCT(BlueprintType)\nstruct FSpectrumData\n{\n\tGENERATED_USTRUCT_BODY()\n\n\t/** The size of displacement map. Must be power of 2.\n\t * Not editable because of FFT shader config */\n\tUPROPERTY(VisibleAnywhere, BlueprintReadOnly)\n\tint32 DispMapDimension;\n\n\t/** The side length (world space) of square patch. Typical value is 1000 ~ 2000. */\n\tUPROPERTY(EditAnywhere)\n\tfloat PatchLength;\n\n\t/** Adjust the time interval for simulation (controls the simulation speed) */\n\tUPROPERTY(EditAnywhere)\n\tfloat TimeScale;\n\n\t/** Amplitude for transverse wave. Around 1.0 (not the world space height). */\n\tUPROPERTY(EditAnywhere)\n\tfloat WaveAmplitude;\n\n\t/** Wind direction. Normalization not required */\n\tUPROPERTY(EditAnywhere)\n\tFVector2D WindDirection;\n\n\t/** The bigger the wind speed, the larger scale of wave crest. But the wave scale can be no larger than PatchLength. Around 100 ~ 1000 */\n\tUPROPERTY(EditAnywhere)\n\tfloat WindSpeed;\n\n\t/** This value damps out the waves against the wind direction. Smaller value means higher wind dependency. */\n\tUPROPERTY(EditAnywhere)\n\tfloat WindDependency;\n\n\t/** The amplitude for longitudinal wave. Higher value creates pointy crests. Must be positive. */\n\tUPROPERTY(EditAnywhere)\n\tfloat ChoppyScale;\n\n\t/** Defaults */\n\tFSpectrumData()\n\t{\n\t\tDispMapDimension = 512;\n\t\tPatchLength = 2000.0f;\n\t\tTimeScale = 0.8f;\n\t\tWaveAmplitude = 0.35f;\n\t\tWindDirection = FVector2D(0.8f, 0.6f);\n\t\tWindSpeed = 600.0f;\n\t\tWindDependency = 0.07f;\n\t\tChoppyScale = 1.3f;\n\t}\n};\n"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanPlugin.cpp",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\nclass FVaOceanPlugin : public IVaOceanPlugin\n{\n\t/** IModuleInterface implementation */\n\tvirtual void StartupModule() override\n\t{\n\n\t}\n\n\tvirtual void ShutdownModule() override\n\t{\n\n\t}\n};\n\nIMPLEMENT_MODULE( FVaOceanPlugin, VaOceanPlugin )\n\nDEFINE_LOG_CATEGORY(LogVaOcean);\n"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanPluginPrivatePCH.h",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"CoreUObject.h\"\n#include \"Engine.h\"\n#include \"UniformBuffer.h\"\n#include \"ShaderParameters.h\"\n#include \"ShaderParameterUtils.h\"\n#include \"GlobalShader.h\"\n#include \"RHIStaticStates.h\"\n\n// You should place include statements to your module's private header files here.  You only need to\n// add includes for headers that are used in most of your module's source files though.\n#include \"ModuleManager.h\"\n\nDECLARE_LOG_CATEGORY_EXTERN(LogVaOcean, Log, All);\n\n#include \"IVaOceanPlugin.h\"\n\n#include \"VaOceanTypes.h\"\n#include \"VaOceanShaders.h\"\n#include \"VaOceanRadixFFT.h\"\n#include \"VaOceanSimulator.h\"\n"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanRadixFFT.cpp",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\nvoid Radix008A(\n\tFRHICommandListImmediate & RHICmdList,\n\tFRadixPlan512* Plan,\n\tuint32 ParamSet,\n\tFUnorderedAccessViewRHIRef pUAV_Dst,\n\tFShaderResourceViewRHIRef pSRV_Src,\n\tuint32 ThreadCount,\n\tuint32 istride)\n{\n\tcheck(ParamSet < FFT_PARAM_SETS);\n\tconst auto FeatureLevel = GMaxRHIFeatureLevel;\n\t// Setup execution configuration\n\tuint32 grid = ThreadCount / COHERENCY_GRANULARITY;\n\n\tFRadixFFTUniformParameters Parameters;\n\tParameters.ThreadCount = Plan->PerFrame[ParamSet].ThreadCount;\n\tParameters.ostride = Plan->PerFrame[ParamSet].ostride;\n\tParameters.istride = Plan->PerFrame[ParamSet].istride;\n\tParameters.pstride = Plan->PerFrame[ParamSet].pstride;\n\tParameters.PhaseBase = Plan->PerFrame[ParamSet].PhaseBase;\n\n\tFRadixFFTUniformBufferRef UniformBuffer =\n\t\tFRadixFFTUniformBufferRef::CreateUniformBufferImmediate(Parameters, EUniformBufferUsage::UniformBuffer_SingleFrame);\n\n\tif (istride > 1)\n\t{\n\t\tTShaderMapRef<FRadix008A_CS> Radix008A_CS(GetGlobalShaderMap(FeatureLevel));\n\t\tRHICmdList.SetComputeShader(Radix008A_CS->GetComputeShader());\n\n\t\tRadix008A_CS->SetParameters(RHICmdList, UniformBuffer);\n\t\tRadix008A_CS->SetParameters(RHICmdList, pSRV_Src, pUAV_Dst);\n\n\t\tRHICmdList.DispatchComputeShader(grid, 1, 1);\n\n\t\tRadix008A_CS->UnsetParameters(RHICmdList);\n\t}\n\telse\n\t{\n\t\tTShaderMapRef<FRadix008A_CS2> Radix008A_CS2(GetGlobalShaderMap(FeatureLevel));\n\t\tRHICmdList.SetComputeShader(Radix008A_CS2->GetComputeShader());\n\n\t\tRadix008A_CS2->SetParameters(RHICmdList, UniformBuffer);\n\t\tRadix008A_CS2->SetParameters(RHICmdList, pSRV_Src, pUAV_Dst);\n\n\t\tRHICmdList.DispatchComputeShader(grid, 1, 1);\n\n\t\tRadix008A_CS2->UnsetParameters(RHICmdList);\n\t}\n}\n\nvoid RadixSetPerFrameParams(FRadixPlan512* Plan,\n\tuint32 ParamSet,\n\tuint32 ThreadCount,\n\tuint32 ostride,\n\tuint32 istride,\n\tuint32 pstride,\n\tfloat PhaseBase)\n{\n\tcheck(ParamSet < FFT_PARAM_SETS);\n\n\tPlan->PerFrame[ParamSet].ThreadCount = ThreadCount;\n\tPlan->PerFrame[ParamSet].ostride = ostride;\n\tPlan->PerFrame[ParamSet].istride = istride;\n\tPlan->PerFrame[ParamSet].pstride = pstride;\n\tPlan->PerFrame[ParamSet].PhaseBase = PhaseBase;\n}\n\nvoid RadixCreatePlan(FRadixPlan512* Plan, uint32 Slices)\n{\n\tPlan->Slices = Slices;\n\n\t// Create 6 param sets for 512x512 transform\n\tconst uint32 thread_count = Plan->Slices * (512 * 512) / 8;\n\tuint32 ostride = 512 * 512 / 8;\n\tuint32 istride = ostride;\n\tuint32 pstride = 512;\n\tdouble phase_base = -TWO_PI / (512.0 * 512.0);\n\n\tRadixSetPerFrameParams(Plan, 0, thread_count, ostride, istride, pstride, (float)phase_base);\n\n\tfor (int i = 1; i < FFT_PARAM_SETS; i++)\n\t{\n\t\tistride /= 8;\n\t\tphase_base *= 8.0;\n\n\t\tif (i == 3)\n\t\t{\n\t\t\tostride /= 512;\n\t\t\tpstride = 1;\n\t\t}\n\n\t\tRadixSetPerFrameParams(Plan, i, thread_count, ostride, istride, pstride, (float)phase_base);\n\t}\n\t\n\t// Temp buffers\n\tuint32 BytesPerElement = sizeof(float) * 2;\n\tuint32 NumElements = (512 * Plan->Slices) * 512;\n\n\tFRHIResourceCreateInfo ResourceCreateInfo;\n\tResourceCreateInfo.BulkData = nullptr;\n\tResourceCreateInfo.ResourceArray = nullptr;\n\tPlan->pBuffer_Tmp = RHICreateStructuredBuffer(BytesPerElement, BytesPerElement * NumElements, (BUF_UnorderedAccess | BUF_ShaderResource), ResourceCreateInfo);\n\n\tPlan->pUAV_Tmp = RHICreateUnorderedAccessView(Plan->pBuffer_Tmp, false, false);\n\tPlan->pSRV_Tmp = RHICreateShaderResourceView(Plan->pBuffer_Tmp);\n}\n\nvoid RadixDestroyPlan(FRadixPlan512* Plan)\n{\n\tPlan->pBuffer_Tmp.SafeRelease();\n\tPlan->pUAV_Tmp.SafeRelease();\n\tPlan->pSRV_Tmp.SafeRelease();\n}\n\nvoid RadixCompute(\n\tFRHICommandListImmediate& RHICmdList,\n\tFRadixPlan512* Plan,\n\tFUnorderedAccessViewRHIRef pUAV_Dst,\n\tFShaderResourceViewRHIRef pSRV_Dst,\n\tFShaderResourceViewRHIRef pSRV_Src)\n{\n\tconst uint32 thread_count = Plan->Slices * (512 * 512) / 8;\n\tuint32 istride = 512 * 512;\n\n\tFUnorderedAccessViewRHIRef pUAV_Tmp = Plan->pUAV_Tmp;\n\tFShaderResourceViewRHIRef pSRV_Tmp = Plan->pSRV_Tmp;\n\n\tistride /= 8;\n\tRadix008A(RHICmdList, Plan, 0, pUAV_Tmp, pSRV_Src, thread_count, istride);\n\n\tistride /= 8;\n\tRadix008A(RHICmdList, Plan, 1, pUAV_Dst, pSRV_Tmp, thread_count, istride);\n\n\tistride /= 8;\n\tRadix008A(RHICmdList, Plan, 2, pUAV_Tmp, pSRV_Dst, thread_count, istride);\n\n\tistride /= 8;\n\tRadix008A(RHICmdList, Plan, 3, pUAV_Dst, pSRV_Tmp, thread_count, istride);\n\n\tistride /= 8;\n\tRadix008A(RHICmdList, Plan, 4, pUAV_Tmp, pSRV_Dst, thread_count, istride);\n\n\tistride /= 8;\n\tRadix008A(RHICmdList, Plan, 5, pUAV_Dst, pSRV_Tmp, thread_count, istride);\n}\n"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanShaders.cpp",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\nIMPLEMENT_SHADER_TYPE(, FUpdateSpectrumCS, TEXT(\"VaOcean_CS\"), TEXT(\"UpdateSpectrumCS\"), SF_Compute);\nIMPLEMENT_SHADER_TYPE(, FRadix008A_CS, TEXT(\"VaOcean_FFT\"), TEXT(\"Radix008A_CS\"), SF_Compute);\nIMPLEMENT_SHADER_TYPE(, FRadix008A_CS2, TEXT(\"VaOcean_FFT\"), TEXT(\"Radix008A_CS2\"), SF_Compute);\n\nIMPLEMENT_SHADER_TYPE(, FQuadVS, TEXT(\"VaOcean_VS_PS\"), TEXT(\"QuadVS\"), SF_Vertex);\nIMPLEMENT_SHADER_TYPE(, FUpdateDisplacementPS, TEXT(\"VaOcean_VS_PS\"), TEXT(\"UpdateDisplacementPS\"), SF_Pixel);\nIMPLEMENT_SHADER_TYPE(, FGenGradientFoldingPS, TEXT(\"VaOcean_VS_PS\"), TEXT(\"GenGradientFoldingPS\"), SF_Pixel);\n\nIMPLEMENT_UNIFORM_BUFFER_STRUCT(FUpdateSpectrumUniformParameters, TEXT(\"PerFrameSp\"));\nIMPLEMENT_UNIFORM_BUFFER_STRUCT(FUpdateDisplacementUniformParameters, TEXT(\"PerFrameDisp\"));\nIMPLEMENT_UNIFORM_BUFFER_STRUCT(FRadixFFTUniformParameters, TEXT(\"PerFrameFFT\"));\n"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanSimulator.cpp",
    "content": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\n#define HALF_SQRT_2\t0.7071068f\n#define GRAV_ACCEL\t981.0f\t// The acceleration of gravity, cm/s^2\n\n#define BLOCK_SIZE_X 16\n#define BLOCK_SIZE_Y 16\n\n/** Vertex declaration for the fullscreen 2D quad */\nTGlobalResource<FQuadVertexDeclaration> GQuadVertexDeclaration;\n\n\n//////////////////////////////////////////////////////////////////////////\n// Height map generation helpers\n\n/** Generating gaussian random number with mean 0 and standard deviation 1 */\nfloat Gauss()\n{\n\tfloat u1 = rand() / (float)RAND_MAX;\n\tfloat u2 = rand() / (float)RAND_MAX;\n\n\tif (u1 < 1e-6f)\n\t{\n\t\tu1 = 1e-6f;\n\t}\n\n\treturn sqrtf(-2 * logf(u1)) * cosf(2 * PI * u2);\n}\n\n/**\n * Phillips Spectrum\n * K: normalized wave vector, W: wind direction, v: wind velocity, a: amplitude constant\n */\nfloat Phillips(FVector2D K, FVector2D W, float v, float a, float dir_depend)\n{\n\t// Largest possible wave from constant wind of velocity v\n\tfloat l = v * v / GRAV_ACCEL;\n\n\t// Damp out waves with very small length w << l\n\tfloat w = l / 1000;\n\n\tfloat Ksqr = K.X * K.X + K.Y * K.Y;\n\tfloat Kcos = K.X * W.X + K.Y * W.Y;\n\tfloat phillips = a * expf(-1 / (l * l * Ksqr)) / (Ksqr * Ksqr * Ksqr) * (Kcos * Kcos);\n\n\t// Filter out waves moving opposite to wind\n\tif (Kcos < 0)\n\t{\n\t\tphillips *= dir_depend;\n\t}\n\n\t// Damp out waves with very small length w << l\n\treturn phillips * expf(-Ksqr * w * w);\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n// Phillips spectrum simulator\n\nAVaOceanSimulator::AVaOceanSimulator(const FObjectInitializer& ObjectInitializer)\n\t: Super(ObjectInitializer)\n{\n\tPrimaryActorTick.bCanEverTick = true;\n\tPrimaryActorTick.TickGroup = TG_DuringPhysics;\n\tbReplicates = true;\n\tNetUpdateFrequency = 10.f;\n\n\tSimulationWorldTime = 0.f;\n\n\t// Vertex to draw on render targets\n\tm_pQuadVB[0].Set(-1.0f, -1.0f, 0.0f, 1.0f);\n\tm_pQuadVB[1].Set(-1.0f,  1.0f, 0.0f, 1.0f);\n\tm_pQuadVB[2].Set( 1.0f, -1.0f, 0.0f, 1.0f);\n\tm_pQuadVB[3].Set( 1.0f,  1.0f, 0.0f, 1.0f);\n}\n\nvoid AVaOceanSimulator::InitializeInternalData()\n{\n\t// Cache shader immutable parameters (looks ugly, but nicely used then)\n\tUpdateSpectrumCSImmutableParams.g_ActualDim = SpectrumConfig.DispMapDimension;\n\tUpdateSpectrumCSImmutableParams.g_InWidth = UpdateSpectrumCSImmutableParams.g_ActualDim + 4;\n\tUpdateSpectrumCSImmutableParams.g_OutWidth = UpdateSpectrumCSImmutableParams.g_ActualDim;\n\tUpdateSpectrumCSImmutableParams.g_OutHeight = UpdateSpectrumCSImmutableParams.g_ActualDim;\n\tUpdateSpectrumCSImmutableParams.g_DtxAddressOffset = FMath::Square(UpdateSpectrumCSImmutableParams.g_ActualDim);\n\tUpdateSpectrumCSImmutableParams.g_DtyAddressOffset = FMath::Square(UpdateSpectrumCSImmutableParams.g_ActualDim) * 2;\n\n\t// Height map H(0)\n\tint32 height_map_size = (SpectrumConfig.DispMapDimension + 4) * (SpectrumConfig.DispMapDimension + 1);\n\tTResourceArray<FVector2D> h0_data;\n\th0_data.Init(FVector2D::ZeroVector, height_map_size);\n\tTResourceArray<float> omega_data;\n\tomega_data.Init(0.0f, height_map_size);\n\tInitHeightMap(SpectrumConfig, h0_data, omega_data);\n\n\tint hmap_dim = SpectrumConfig.DispMapDimension;\n\tint input_full_size = (hmap_dim + 4) * (hmap_dim + 1);\n\t// This value should be (hmap_dim / 2 + 1) * hmap_dim, but we use full sized buffer here for simplicity.\n\tint input_half_size = hmap_dim * hmap_dim;\n\tint output_size = hmap_dim * hmap_dim;\n\n\t// For filling the buffer with zeroes\n\tTResourceArray<float> zero_data;\n\tzero_data.Init(0.0f, 3 * output_size * 2);\n\n\t// RW buffer allocations\n\t// H0\n\tuint32 float2_stride = 2 * sizeof(float);\n\tCreateBufferAndUAV(&h0_data, input_full_size * float2_stride, float2_stride, &m_pBuffer_Float2_H0, &m_pUAV_H0, &m_pSRV_H0);\n\n\t// Notice: The following 3 buffers should be half sized buffer because of conjugate symmetric input. But\n\t// we use full sized buffers due to the CS4.0 restriction.\n\n\t// Put H(t), Dx(t) and Dy(t) into one buffer because CS4.0 allows only 1 UAV at a time\n\tCreateBufferAndUAV(&zero_data, 3 * input_half_size * float2_stride, float2_stride, &m_pBuffer_Float2_Ht, &m_pUAV_Ht, &m_pSRV_Ht);\n\n\t// omega\n\tCreateBufferAndUAV(&omega_data, input_full_size * sizeof(float), sizeof(float), &m_pBuffer_Float_Omega, &m_pUAV_Omega, &m_pSRV_Omega);\n\n\t// Re-init the array because it was discarded by previous buffer creation\n\tzero_data.Empty();\n\tzero_data.Init(0.0f, 3 * output_size * 2);\n\t// Notice: The following 3 should be real number data. But here we use the complex numbers and C2C FFT\n\t// due to the CS4.0 restriction.\n\t// Put Dz, Dx and Dy into one buffer because CS4.0 allows only 1 UAV at a time\n\tCreateBufferAndUAV(&zero_data, 3 * output_size * float2_stride, float2_stride, &m_pBuffer_Float_Dxyz, &m_pUAV_Dxyz, &m_pSRV_Dxyz);\n\n\t// FFT\n\tRadixCreatePlan(&FFTPlan, 3); \n\n\t// Turn the flag on\n\tbSimulatorInitializated = true;\n}\n\nvoid AVaOceanSimulator::InitHeightMap(const FSpectrumData& Params, TResourceArray<FVector2D>& out_h0, TResourceArray<float>& out_omega)\n{\n\tint32 i, j;\n\tFVector2D K, Kn;\n\n\tFVector2D wind_dir = Params.WindDirection;\n\twind_dir.Normalize();\n\n\tfloat a = Params.WaveAmplitude * 1e-7f;\t// It is too small. We must scale it for editing.\n\tfloat v = Params.WindSpeed;\n\tfloat dir_depend = Params.WindDependency;\n\n\tint height_map_dim = Params.DispMapDimension;\n\tfloat patch_length = Params.PatchLength;\n\n\t// Initialize random generator.\n\tsrand(0);\n\n\tfor (i = 0; i <= height_map_dim; i++)\n\t{\n\t\t// K is wave-vector, range [-|DX/W, |DX/W], [-|DY/H, |DY/H]\n\t\tK.Y = (-height_map_dim / 2.0f + i) * (2 * PI / patch_length);\n\n\t\tfor (j = 0; j <= height_map_dim; j++)\n\t\t{\n\t\t\tK.X = (-height_map_dim / 2.0f + j) * (2 * PI / patch_length);\n\n\t\t\tfloat phil = (K.X == 0 && K.Y == 0) ? 0 : sqrtf(Phillips(K, wind_dir, v, a, dir_depend));\n\n\t\t\tout_h0[i * (height_map_dim + 4) + j].X = float(phil * Gauss() * HALF_SQRT_2);\n\t\t\tout_h0[i * (height_map_dim + 4) + j].Y = float(phil * Gauss() * HALF_SQRT_2);\n\n\t\t\t// The angular frequency is following the dispersion relation:\n\t\t\t//            out_omega^2 = g*k\n\t\t\t// The equation of Gerstner wave:\n\t\t\t//            x = x0 - K/k * A * sin(dot(K, x0) - sqrt(g * k) * t), x is a 2D vector.\n\t\t\t//            z = A * cos(dot(K, x0) - sqrt(g * k) * t)\n\t\t\t// Gerstner wave shows that a point on a simple sinusoid wave is doing a uniform circular\n\t\t\t// motion with the center (x0, y0, z0), radius A, and the circular plane is parallel to\n\t\t\t// vector K.\n\t\t\tout_omega[i * (height_map_dim + 4) + j] = sqrtf(GRAV_ACCEL * sqrtf(K.X * K.X + K.Y * K.Y));\n\t\t}\n\t}\n}\n\nvoid AVaOceanSimulator::CreateBufferAndUAV(FResourceArrayInterface* Data, uint32 byte_width, uint32 byte_stride,\n\tFStructuredBufferRHIRef* ppBuffer, FUnorderedAccessViewRHIRef* ppUAV, FShaderResourceViewRHIRef* ppSRV)\n{\n\tFRHIResourceCreateInfo ResourceCreateInfo;\n\tResourceCreateInfo.ResourceArray = Data;\n\t*ppBuffer = RHICreateStructuredBuffer(byte_stride, Data->GetResourceDataSize(), (BUF_UnorderedAccess | BUF_ShaderResource), ResourceCreateInfo);\n\n\t*ppUAV = RHICreateUnorderedAccessView(*ppBuffer, false, false);\n\t*ppSRV = RHICreateShaderResourceView(*ppBuffer);\n}\n\nvoid AVaOceanSimulator::ClearInternalData()\n{\n\tRadixDestroyPlan(&FFTPlan);\n\n\tm_pBuffer_Float2_H0.SafeRelease();\n\tm_pUAV_H0.SafeRelease();\n\tm_pSRV_H0.SafeRelease();\n\n\tm_pBuffer_Float_Omega.SafeRelease();\n\tm_pUAV_Omega.SafeRelease();\n\tm_pSRV_Omega.SafeRelease();\n\n\tm_pBuffer_Float2_Ht.SafeRelease();\n\tm_pUAV_Ht.SafeRelease();\n\tm_pSRV_Ht.SafeRelease();\n\n\tm_pBuffer_Float_Dxyz.SafeRelease();\n\tm_pUAV_Dxyz;\n\tm_pSRV_Dxyz;\n\n\tbSimulatorInitializated = false;\n}\n\nvoid AVaOceanSimulator::ResetInternalData()\n{\n\tClearInternalData();\n\tInitializeInternalData();\n}\n\nvoid AVaOceanSimulator::BeginDestroy()\n{\n\tClearInternalData();\n\n\tSuper::BeginDestroy();\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n// Simulation\n\n#if WITH_EDITOR\nvoid AVaOceanSimulator::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)\n{\n\t// AActor::PostEditChange will ForceUpdateComponents()\n\tSuper::PostEditChangeProperty(PropertyChangedEvent);\n\n\t// @todo Update shader configuration\n}\n#endif // WITH_EDITOR\n\nbool AVaOceanSimulator::ShouldTickIfViewportsOnly() const\n{\n\treturn true;\n}\n\nvoid AVaOceanSimulator::Tick(float DeltaSeconds)\n{\n\tSuper::Tick(DeltaSeconds);\n\n\t// Check that data is initializated\n\tif (!bSimulatorInitializated)\n\t{\n\t\tInitializeInternalData();\n\t}\n\n\t// Tick world time\n\tSimulationWorldTime += DeltaSeconds;\n\n\t// Process simulation shaders\n\tUpdateDisplacementMap(SimulationWorldTime);\n}\n\nvoid AVaOceanSimulator::UpdateDisplacementMap(float WorldTime)\n{\n\tif (!DisplacementTexture || !GradientTexture)\n\t\treturn;\n\n\t// ---------------------------- H(0) -> H(t), D(x, t), D(y, t) --------------------------------\n\tFUpdateSpectrumCSPerFrame UpdateSpectrumCSPerFrameParams;\n\tUpdateSpectrumCSPerFrameParams.g_Time = WorldTime * SpectrumConfig.TimeScale;\n\tUpdateSpectrumCSPerFrameParams.g_ChoppyScale = SpectrumConfig.ChoppyScale;\n\tUpdateSpectrumCSPerFrameParams.m_pSRV_H0 = m_pSRV_H0;\n\tUpdateSpectrumCSPerFrameParams.m_pSRV_Omega = m_pSRV_Omega;\n\tUpdateSpectrumCSPerFrameParams.m_pUAV_Ht = m_pUAV_Ht;\n\n\tENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(\n\t\tUpdateSpectrumCSCommand,\n\t\tFUpdateSpectrumCSImmutable, ImmutableParams, UpdateSpectrumCSImmutableParams,\n\t\tFUpdateSpectrumCSPerFrame, PerFrameParams, UpdateSpectrumCSPerFrameParams,\n\t\t{\n\t\t\tFUpdateSpectrumUniformParameters Parameters;\n\t\t\tconst auto FeatureLevel = GMaxRHIFeatureLevel;\n\t\t\tParameters.Time = PerFrameParams.g_Time;\n\n\t\t\tFUpdateSpectrumUniformBufferRef UniformBuffer = \n\t\t\t\tFUpdateSpectrumUniformBufferRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_SingleFrame);\n\n\t\t\tTShaderMapRef<FUpdateSpectrumCS> UpdateSpectrumCS(GetGlobalShaderMap(GMaxRHIFeatureLevel));\n\t\t\tRHICmdList.SetComputeShader(UpdateSpectrumCS->GetComputeShader());\n\n\t\t\tUpdateSpectrumCS->SetParameters(RHICmdList, ImmutableParams.g_ActualDim,\n\t\t\t\tImmutableParams.g_InWidth, ImmutableParams.g_OutWidth, ImmutableParams.g_OutHeight,\n\t\t\t\tImmutableParams.g_DtxAddressOffset, ImmutableParams.g_DtyAddressOffset);\n\n\t\t\tUpdateSpectrumCS->SetParameters(RHICmdList, UniformBuffer, PerFrameParams.m_pSRV_H0, PerFrameParams.m_pSRV_Omega);\n\t\t\tUpdateSpectrumCS->SetOutput(RHICmdList, PerFrameParams.m_pUAV_Ht);\n\n\t\t\tuint32 group_count_x = (ImmutableParams.g_ActualDim + BLOCK_SIZE_X - 1) / BLOCK_SIZE_X;\n\t\t\tuint32 group_count_y = (ImmutableParams.g_ActualDim + BLOCK_SIZE_Y - 1) / BLOCK_SIZE_Y;\n\t\t\tRHICmdList.DispatchComputeShader(group_count_x, group_count_y, 1);\n\n\t\t\tUpdateSpectrumCS->UnsetParameters(RHICmdList);\n\t\t\tUpdateSpectrumCS->UnbindBuffers(RHICmdList);\n\t\t});\n\n\t// ------------------------------------ Perform FFT -------------------------------------------\n\tENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(\n\t\tRadixFFTCommand,\n\t\tFRadixPlan512*, pPlan, &FFTPlan,\n\t\tFUnorderedAccessViewRHIRef, m_pUAV_Dxyz, m_pUAV_Dxyz,\n\t\tFShaderResourceViewRHIRef, m_pSRV_Dxyz, m_pSRV_Dxyz,\n\t\tFShaderResourceViewRHIRef, m_pSRV_Ht, m_pSRV_Ht,\n\t\t{\n\t\t\tRadixCompute(RHICmdList, pPlan, m_pUAV_Dxyz, m_pSRV_Dxyz, m_pSRV_Ht);\n\t\t});\n\n\t// --------------------------------- Wrap Dx, Dy and Dz ---------------------------------------\n\tFUpdateDisplacementPSPerFrame UpdateDisplacementPSPerFrameParams;\n\tUpdateDisplacementPSPerFrameParams.g_ChoppyScale = SpectrumConfig.ChoppyScale;\n\tUpdateDisplacementPSPerFrameParams.g_GridLen = SpectrumConfig.DispMapDimension / SpectrumConfig.PatchLength;\n\tUpdateDisplacementPSPerFrameParams.g_InputDxyz = m_pSRV_Dxyz;\n\tFMemory::Memcpy(UpdateDisplacementPSPerFrameParams.m_pQuadVB, m_pQuadVB, sizeof(m_pQuadVB[0]) * 4);\n\n\tFTextureRenderTargetResource* DisplacementRenderTarget = DisplacementTexture->GameThread_GetRenderTargetResource();\n\n\tENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(\n\t\tUpdateDisplacementPSCommand,\n\t\tFTextureRenderTargetResource*, TextureRenderTarget, DisplacementRenderTarget,\n\t\tFUpdateSpectrumCSImmutable, ImmutableParams, UpdateSpectrumCSImmutableParams,\t\t// We're using the same params as for CS\n\t\tFUpdateDisplacementPSPerFrame, PerFrameParams, UpdateDisplacementPSPerFrameParams,\n\t\t{\n\t\t\tconst auto FeatureLevel = GMaxRHIFeatureLevel;\n\t\t\tFUpdateDisplacementUniformParameters Parameters;\n\t\t\tParameters.ChoppyScale = PerFrameParams.g_ChoppyScale;\n\t\t\tParameters.GridLen = PerFrameParams.g_GridLen;\n\n\t\t\tFUpdateDisplacementUniformBufferRef UniformBuffer =\n\t\t\t\tFUpdateDisplacementUniformBufferRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_SingleFrame);\n\n\t\t\tSetRenderTarget(RHICmdList, TextureRenderTarget->GetRenderTargetTexture(), NULL);\n\t\t\tRHICmdList.Clear(true, FLinearColor::Transparent, false, 0.f, false, 0, FIntRect());\n\t\t\t\n\t\t\t// Be sure we're blending right without any alpha influence on Color blending\n\t\t\tRHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());\n\n\t\t\tTShaderMapRef<FQuadVS> QuadVS(GetGlobalShaderMap(GMaxRHIFeatureLevel));\n\t\t\tTShaderMapRef<FUpdateDisplacementPS> UpdateDisplacementPS(GetGlobalShaderMap(GMaxRHIFeatureLevel));\n\n\t\t\tstatic FGlobalBoundShaderState UpdateDisplacementBoundShaderState;\n\t\t\tSetGlobalBoundShaderState(RHICmdList, GMaxRHIFeatureLevel, UpdateDisplacementBoundShaderState, GQuadVertexDeclaration.VertexDeclarationRHI, *QuadVS, *UpdateDisplacementPS);\n\n\t\t\tUpdateDisplacementPS->SetParameters(RHICmdList, ImmutableParams.g_ActualDim,\n\t\t\t\tImmutableParams.g_InWidth, ImmutableParams.g_OutWidth, ImmutableParams.g_OutHeight,\n\t\t\t\tImmutableParams.g_DtxAddressOffset, ImmutableParams.g_DtyAddressOffset);\n\n\t\t\tUpdateDisplacementPS->SetParameters(RHICmdList, UniformBuffer, PerFrameParams.g_InputDxyz);\n\n\t\t\tDrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, PerFrameParams.m_pQuadVB, sizeof(PerFrameParams.m_pQuadVB[0]));\n\n\t\t\tUpdateDisplacementPS->UnsetParameters(RHICmdList);\n\t\t});\n\n\t// ----------------------------------- Generate Normal ----------------------------------------\n\tFGenGradientFoldingPSPerFrame GenGradientFoldingPSPerFrameParams;\n\tGenGradientFoldingPSPerFrameParams.g_ChoppyScale = SpectrumConfig.ChoppyScale;\n\tGenGradientFoldingPSPerFrameParams.g_GridLen = SpectrumConfig.DispMapDimension / SpectrumConfig.PatchLength;\n\tFMemory::Memcpy(GenGradientFoldingPSPerFrameParams.m_pQuadVB, m_pQuadVB, sizeof(m_pQuadVB[0]) * 4);\n\n\tFTextureRenderTargetResource* GradientRenderTarget = GradientTexture->GameThread_GetRenderTargetResource();\n\n\tENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(\n\t\tGenGradientFoldingPSCommand,\n\t\tFTextureRenderTargetResource*, TextureRenderTarget, GradientRenderTarget,\n\t\tFUpdateSpectrumCSImmutable, ImmutableParams, UpdateSpectrumCSImmutableParams,\t\t// We're using the same params as for CS\n\t\tFGenGradientFoldingPSPerFrame, PerFrameParams, GenGradientFoldingPSPerFrameParams,\n\t\tFTextureRenderTargetResource*, DisplacementRenderTarget, DisplacementRenderTarget,\n\t\t{\n\t\t\tFUpdateDisplacementUniformParameters Parameters;\n\t\t\tconst auto FeatureLevel = GMaxRHIFeatureLevel;\n\t\t\tParameters.ChoppyScale = PerFrameParams.g_ChoppyScale;\n\t\t\tParameters.GridLen = PerFrameParams.g_GridLen;\n\n\t\t\tFUpdateDisplacementUniformBufferRef UniformBuffer = FUpdateDisplacementUniformBufferRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_SingleFrame);\n\n\t\t\tSetRenderTarget(RHICmdList, TextureRenderTarget->GetRenderTargetTexture(), FTextureRHIRef());\n\t\t\tRHICmdList.Clear(true, FLinearColor::Transparent, false, 0.f, false, 0, FIntRect());\n\n\t\t\t// Be sure we're blending right without any alpha influence on Color blending\n\t\t\tRHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());\n\n\t\t\tTShaderMapRef<FQuadVS> QuadVS(GetGlobalShaderMap(GMaxRHIFeatureLevel));\n\t\t\tTShaderMapRef<FGenGradientFoldingPS> GenGradientFoldingPS(GetGlobalShaderMap(GMaxRHIFeatureLevel));\n\n\t\t\tstatic FGlobalBoundShaderState UpdateDisplacementBoundShaderState;\n\t\t\tSetGlobalBoundShaderState(RHICmdList, GMaxRHIFeatureLevel, UpdateDisplacementBoundShaderState, GQuadVertexDeclaration.VertexDeclarationRHI, *QuadVS, *GenGradientFoldingPS);\n\n\t\t\tGenGradientFoldingPS->SetParameters(RHICmdList, ImmutableParams.g_ActualDim,\n\t\t\t\tImmutableParams.g_InWidth, ImmutableParams.g_OutWidth, ImmutableParams.g_OutHeight,\n\t\t\t\tImmutableParams.g_DtxAddressOffset, ImmutableParams.g_DtyAddressOffset);\n\n\t\t\tGenGradientFoldingPS->SetParameters(RHICmdList, UniformBuffer, DisplacementRenderTarget->TextureRHI);\n\n\t\t\tDrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, PerFrameParams.m_pQuadVB, sizeof(PerFrameParams.m_pQuadVB[0]));\n\n\t\t\tGenGradientFoldingPS->UnsetParameters(RHICmdList);\n\n\t\t\t// Generate new mipmaps now\n\t\t\tRHICmdList.GenerateMips(TextureRenderTarget->TextureRHI);\n\t});\n\t\n}\n\n//////////////////////////////////////////////////////////////////////////\n// Spectrum configuration\n\nconst FSpectrumData& AVaOceanSimulator::GetSpectrumConfig() const\n{\n\treturn SpectrumConfig;\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n// Utilities\n\nUTextureRenderTarget2D* AVaOceanSimulator::CreateRenderTarget(bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint& InTargetSize)\n{\n\tUTextureRenderTarget2D* NewRenderTarget = NewObject<UTextureRenderTarget2D>(this);\n\tcheck(NewRenderTarget);\n\n\tSetupRenderTarget(NewRenderTarget, bInForceLinearGamma, bNormalMap, InPixelFormat, InTargetSize);\n\n\treturn NewRenderTarget;\n}\n\nvoid AVaOceanSimulator::SetupRenderTarget(UTextureRenderTarget2D * InRenderTarget, bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint & InTargetSize)\n{\n\tconst FLinearColor ClearColor = bNormalMap ? FLinearColor(0.0f, 0.0f, 0.0f, 0.0f) : FLinearColor(1.0f, 0.0f, 1.0f, 0.0f);\n\n\tInRenderTarget->ClearColor = ClearColor;\n\tInRenderTarget->TargetGamma = 0.0f;\n\tInRenderTarget->InitCustomFormat(InTargetSize.X, InTargetSize.Y, InPixelFormat, bInForceLinearGamma);\n}\n"
  },
  {
    "path": "Source/VaOceanPlugin/Public/IVaOceanPlugin.h",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"ModuleManager.h\"\n\n\n/**\n * The public interface to this module.  In most cases, this interface is only public to sibling modules \n * within this plugin.\n */\nclass IVaOceanPlugin : public IModuleInterface\n{\n\npublic:\n\n\t/**\n\t * Singleton-like access to this module's interface.  This is just for convenience!\n\t * Beware of calling this during the shutdown phase, though.  Your module might have been unloaded already.\n\t *\n\t * @return Returns singleton instance, loading the module on demand if needed\n\t */\n\tstatic inline IVaOceanPlugin& Get()\n\t{\n\t\treturn FModuleManager::LoadModuleChecked< IVaOceanPlugin >( \"VaOceanPlugin\" );\n\t}\n\n\t/**\n\t * Checks to see if this module is loaded and ready.  It is only valid to call Get() if IsAvailable() returns true.\n\t *\n\t * @return True if the module is loaded and ready to use\n\t */\n\tstatic inline bool IsAvailable()\n\t{\n\t\treturn FModuleManager::Get().IsModuleLoaded( \"VaOceanPlugin\" );\n\t}\n};\n\n"
  },
  {
    "path": "Source/VaOceanPlugin/VaOceanPlugin.Build.cs",
    "content": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\nnamespace UnrealBuildTool.Rules\n{\n\tpublic class VaOceanPlugin : ModuleRules\n\t{\n        public VaOceanPlugin(TargetInfo Target)\n\t\t{\n\t\t\tPublicIncludePaths.AddRange(\n\t\t\t\tnew string[] { \n\t\t\t\t\t// ... add public include paths required here ...\n\t\t\t\t}\n\t\t\t\t);\n\n\t\t\tPrivateIncludePaths.AddRange(\n\t\t\t\tnew string[] {\n\t\t\t\t\t\"VaOceanPlugin/Private\",\n                    // ... add other private include paths required here ...\n\t\t\t\t}\n\t\t\t\t);\n\n\t\t\tPublicDependencyModuleNames.AddRange(\n\t\t\t\tnew string[]\n\t\t\t\t{\n\t\t\t\t\t\"Core\",\n\t\t\t\t\t\"CoreUObject\",\n                    \"Engine\",\n                    \"RenderCore\",\n                    \"ShaderCore\",\n                    \"RHI\"\n                    // ... add other public dependencies that you statically link with here ...\n\t\t\t\t}\n\t\t\t\t);\n\n\t\t\tPrivateDependencyModuleNames.AddRange(\n\t\t\t\tnew string[]\n\t\t\t\t{\n\t\t\t\t\t// ... add private dependencies that you statically link with here ...\n\t\t\t\t}\n\t\t\t\t);\n\n\t\t\tDynamicallyLoadedModuleNames.AddRange(\n\t\t\t\tnew string[]\n\t\t\t\t{\n\t\t\t\t\t// ... add any modules that your module loads dynamically here ...\n\t\t\t\t}\n\t\t\t\t);\n\t\t}\n\t}\n}"
  },
  {
    "path": "VaOceanPlugin.uplugin",
    "content": "{\n    \"FileVersion\" : 3,\n\t\n\t\"FriendlyName\" : \"VaOcean\",\n\t\"Version\" : 7,\n\t\"VersionName\" : \"0.5-a1\",\n\t\"CreatedBy\" : \"Vladimir Alyamkin\",\n\t\"CreatedByURL\" : \"http://alyamkin.com\",\n\t\"EngineVersion\" : \"4.12.0\",\n\t\"Description\" : \"Ocean surface simulation plugin\",\n\t\"Category\" : \"Environment\",\n\t\"EnabledByDefault\" : false,\n\t\"CanContainContent\" : true,\n\t\n\t\"Modules\" :\n\t[\n\t\t{\n\t\t\t\"Name\" : \"VaOceanPlugin\",\n\t\t\t\"Type\" : \"Runtime\",\n\t\t\t\"LoadingPhase\" : \"PostConfigInit\"\n\t\t}\n\t]\n}"
  }
]