//+------------------------------------------------------------------+ //| Seascape.mq5 | //| Copyright 2016, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2016, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| OpenCL code | //+------------------------------------------------------------------+ //| Based on pixel shader by Alexander Alekseev aka TDM-2014 | //| https://www.shadertoy.com/view/Ms2SD1 | //+------------------------------------------------------------------+ const string cl_src= "#define NUM_STEPS (int)8\r\n" "#define PI (float)3.1415\r\n" "#define EPSILON (float)1e-3\r\n" "#define EPSILON_NRM ((float)0.1/iResolution.x)\r\n" "#define ITER_GEOMETRY (int)3\r\n" "#define ITER_FRAGMENT (int)5\r\n" "#define SEA_HEIGHT (float)0.6\r\n" "#define SEA_CHOPPY (float)4.0\r\n" "#define SEA_SPEED (float)0.8\r\n" "#define SEA_FREQ (float)0.16\r\n" "#define SEA_BASE vec3(0.1,0.19,0.22)\r\n" "#define SEA_WATER_COLOR vec3(0.8,0.9,0.6)\r\n" "#define SEA_TIME ((float)1.0 + iGlobalTime * SEA_SPEED)\r\n" "float max1(float v1,float v2) { if (v1>v2) return v1; return v2; }\r\n" "float dot2(float2 v1,float2 v2) { return v1.x*v2.x+v1.y*v2.y; }\r\n" "float dot3(float3 v1,float3 v2) { return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z; }\r\n" "float fract1(float p) { return p-floor(p); }\r\n" "float2 fract2(float2 p) { return p-floor(p); }\r\n" "float mix1(float x1,float x2,float a) { return(x1+(x2-x1)*a); }\r\n" "float2 mix2(float2 x1,float2 x2,float2 a) { float2 r={x1.x+(x2.x-x1.x)*a.x,x1.y+(x2.y-x1.y)*a.y }; return(r); }\r\n" "float3 mix3(float3 x1,float3 x2,float3 a) { float3 r={x1.x+(x2.x-x1.x)*a.x,x1.y+(x2.y-x1.y)*a.y,x1.z+(x2.z-x1.z)*a.z }; return(r); }\r\n" "float3 vec31(float x) { float3 r={x,x,x}; return(r); }\r\n" "float3 vec3(float x,float y,float z) { float3 r={x,y,z}; return(r); }\r\n" "float2 vec2(float x,float y) { float2 r={x,y}; return(r); }\r\n" "float4 vec4(float3 x,float y) { float4 r={x.x,x.y,x.z,y}; return(r); }\r\n" "float3 reflect3(float3 I,float3 N) { return(I-(float)2.0*dot3(N,I)*N); } \r\n" "float diffuse(float3 n,float3 l,float p) { return pow(dot3(n,l) * (float)0.4 + (float)0.6,p); }\r\n" "float2 abs2(float2 f) { if(f.x<0) f.x=-f.x; if(f.y<0) f.y=-f.y; return(f); }\r\n" "float hash(float2 p) { return fract1(sin(dot2(p,vec2((float)127.1,(float)311.7)))*43758.5453123); }\r\n" "float specular(float3 n,float3 l,float3 e,float s) { return pow(max1(dot3(reflect3(e,n),l),0.0),s)*((s+(float)8.0)/(float)(3.1415 * 8.0)); }\r\n" "float3 getSkyColor(float3 e)\r\n" " {\r\n" " e.y=max1(e.y,0.0);\r\n" " float3 r2;\r\n" " r2.x = pow((float)1.0-e.y,(float)2.0);\r\n" " r2.y = (float)1.0-e.y;\r\n" " r2.z = (float)0.6+((float)1.0-e.y)*(float)0.4;\r\n" " return r2;\r\n" " }\r\n" "void fromEuler(float3 ang,float3 *r1,float3 *r2,float3 *r3)\r\n" " {\r\n" " float2 a1 = vec2(sin(ang.x),cos(ang.x));\r\n" " float2 a2 = vec2(sin(ang.y),cos(ang.y));\r\n" " float2 a3 = vec2(sin(ang.z),cos(ang.z));\r\n" " *r1 = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);\r\n" " *r2 = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);\r\n" " *r3 = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);\r\n" " }\r\n" "float noise(float2 p) \r\n" " {\r\n" " float2 i = floor(p);\r\n" " float2 f = fract2(p);\r\n" " float2 u = f * f * ((float)3.0 - (float)2.0 * f);\r\n" " float mx1=mix1(hash(i+vec2(0.0,0.0)),hash(i+vec2(1.0,0.0)),u.x);\r\n" " float mx2=mix1(hash(i+vec2(0.0,1.0)),hash(i+vec2(1.0,1.0)),u.x);\r\n" " return (float)-1.0 + (float)2.0*mix(mx1,mx2,u.y);\r\n" " }\r\n" "float sea_octave(float2 uv, float choppy)\r\n" " {\r\n" " uv += noise(uv);\r\n" " float2 wv = (float)1.0-abs2(sin(uv));\r\n" " float2 swv = abs2(cos(uv));\r\n" " wv = mix2(wv,swv,wv);\r\n" " return pow((float)1.0-pow(wv.x * wv.y,(float)0.65),choppy);\r\n" " }\r\n" "float map(float3 p,float iGlobalTime)\r\n" " {\r\n" " float freq = SEA_FREQ;\r\n" " float amp = SEA_HEIGHT;\r\n" " float choppy = SEA_CHOPPY;\r\n" " float2 uv = p.xz; uv.x *= (float)0.75;\r\n" " float d, h = 0.0;\r\n" " for(int i = 0; i < ITER_GEOMETRY; i++)\r\n" " {\r\n" " d = sea_octave((uv+SEA_TIME)*freq,choppy);\r\n" " d += sea_octave((uv-SEA_TIME)*freq,choppy);\r\n" " h += d * amp;\r\n" " float2 uvt={(float)1.6*uv.x+(float)1.2*uv.y, (float)-1.2*uv.x+(float)1.6*uv.y };\r\n" " uv = uvt;\r\n" " freq *= (float)1.9; amp *= (float)0.22;\r\n" " choppy = mix1(choppy,(float)1.0,(float)0.2);\r\n" " }\r\n" " return p.y - h;\r\n" " }\r\n" "float map_detailed(float3 p,float iGlobalTime)\r\n" " {\r\n" " float freq = SEA_FREQ;\r\n" " float amp = SEA_HEIGHT;\r\n" " float choppy = SEA_CHOPPY;\r\n" " float2 uv = p.xz; uv.x *= (float)0.75;\r\n" " float d, h = 0.0;\r\n" " for(int i = 0; i < ITER_FRAGMENT; i++)\r\n" " {\r\n" " d =sea_octave((uv+SEA_TIME)*freq,choppy);\r\n" " d+=sea_octave((uv-SEA_TIME)*freq,choppy);\r\n" " h+=d * amp;\r\n" " float2 uvt={ (float)1.6*uv.x+(float)1.2*uv.y, (float)-1.2*uv.x+(float)1.6*uv.y };\r\n" " uv = uvt;\r\n" " freq *= (float)1.9; amp *= (float)0.22;\r\n" " choppy = mix1(choppy,(float)1.0,(float)0.2);\r\n" " }\r\n" " return p.y - h;\r\n" " }\r\n" "float3 getSeaColor(float3 p, float3 n, float3 l, float3 eye, float3 dist)\r\n" " {\r\n" " float fresnel = clamp((float)1.0 - dot3(n,-eye), (float)0.0, (float)1.0);\r\n" " fresnel = pow(fresnel,(float)3.0) * (float)0.65;\r\n" " float3 reflected = getSkyColor(reflect3(eye,n));\r\n" " float3 refracted = SEA_BASE + diffuse(n,l,(float)80.0) * SEA_WATER_COLOR * (float)0.12; \r\n" " float3 color = mix3(refracted,reflected,fresnel);\r\n" " float atten = max1((float)1.0 - dot(dist,dist) * (float)0.001, (float)0.0);\r\n" " color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * (float)0.18 * atten;\r\n" " color += vec31(specular(n,l,eye,(float)60.0));\r\n" " return color;\r\n" " }\r\n" "float3 getNormal(float3 p, float eps,float iGlobalTime)\r\n" " {\r\n" " float3 n;\r\n" " n.y = map_detailed(p,iGlobalTime);\r\n" " n.x = map_detailed(vec3(p.x+eps,p.y,p.z),iGlobalTime) - n.y;\r\n" " n.z = map_detailed(vec3(p.x,p.y,p.z+eps),iGlobalTime) - n.y;\r\n" " n.y = eps;\r\n" " return normalize(n);\r\n" " }\r\n" "float heightMapTracing(float3 ori, float3 dir,float3 *p,float iGlobalTime)\r\n" " { \r\n" " float tm = (float)0.0;\r\n" " float tx = (float)1000.0;\r\n" " float hx = map(ori + dir * tx,iGlobalTime);\r\n" " if(hx > (float)0.0) return tx; \r\n" " float hm = map(ori + dir * tm,iGlobalTime);\r\n" " float tmid = (float)0.0;\r\n" " for(int i = 0; i < NUM_STEPS; i++)\r\n" " {\r\n" " tmid = mix(tm,tx, hm/(hm-hx));\r\n" " *p = ori + dir * tmid;\r\n" " float hmid = map(*p,iGlobalTime);\r\n" " if(hmid < (float)0.0)\r\n" " {\r\n" " tx = tmid;\r\n" " hx = hmid;\r\n" " }\r\n" " else\r\n" " {\r\n" " tm = tmid;\r\n" " hm = hmid;\r\n" " }\r\n" " }\r\n" " return tmid;\r\n" " }\r\n" "float4 mainImage(float2 fragCoord,float iGlobalTime,float2 iResolution)\r\n" " {\r\n" " float4 fragColor;\r\n" " float2 iMouse= {0,0};\r\n" " float2 uv = fragCoord.xy / iResolution;\r\n" " uv = uv * (float)2.0 - (float)1.0;\r\n" " uv.x *= iResolution.x / iResolution.y;\r\n" " float time = iGlobalTime * (float)0.3 + iMouse.x*(float)0.01;\r\n" " float3 ang = vec3(sin(time*(float)3.0)*(float)0.1,sin(time)*(float)0.2+(float)0.3,time);\r\n" " float3 ori = vec3(0.0,3.5,time*(float)5.0);\r\n" " float3 dir = normalize(vec3(uv.x,uv.y,(float)-2.0)); dir.z += length(uv) * (float)0.15;\r\n" " dir = normalize(dir);\r\n" " float3 r1,r2,r3;\r\n" " fromEuler(ang,&r1,&r2,&r3);\r\n" " float3 r;\r\n" " r.x=r1.x*dir.x+r1.y*dir.y+r1.z*dir.z;\r\n" " r.y=r2.x*dir.x+r2.y*dir.y+r2.z*dir.z;\r\n" " r.z=r3.x*dir.x+r3.y*dir.y+r3.z*dir.z;\r\n" " dir=r;\r\n" " float3 p;\r\n" " heightMapTracing(ori,dir,&p,iGlobalTime);\r\n" " float3 dist = p - ori;\r\n" " float3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM,iGlobalTime);\r\n" " float3 light = normalize(vec3((float)0.0,(float)1.0,(float)0.8));\r\n" " float3 color = mix(getSkyColor(dir),getSeaColor(p,n,light,dir,dist),pow(smoothstep((float)0.0,(float)-0.05,dir.y),(float)0.3));\r\n" " fragColor = vec4(pow(color,vec31((float)0.75)),(float)1.0);\r\n" " return(fragColor);\r\n" " }\r\n" "__kernel void Seascape(float iGlobalTime,__global uint *out)\r\n" " {\r\n" " size_t w = get_global_size(0);\r\n" " size_t h = get_global_size(1);\r\n" " float2 iRes = {(float)w,(float)h};\r\n" " size_t gx = get_global_id(0);\r\n" " size_t gy = get_global_id(1);\r\n" " float2 coord={gx,gy};\r\n" " float4 res=mainImage(coord,iGlobalTime,iRes);\r\n" " uint b=(uint)(res.z*255);\r\n" " uint g=(uint)(res.y*255);\r\n" " uint r=(uint)(res.x*255);\r\n" " if(b>255) b=255;\r\n" " if(r>255) r=255;\r\n" " if(g>255) g=255;\r\n" " out[w*((uint)(iRes.y-1)-gy)+gx] = (r<<16)|(g<<8)|b;\r\n" " }\r\n"; uint ExtSizeX=640; // Width uint ExtSizeY=360; // Height //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void ClearChart(void) { //--- ChartSetInteger(0,CHART_SHOW_ASK_LINE,false); ChartSetInteger(0,CHART_SHOW_BID_LINE,false); ChartSetInteger(0,CHART_SHOW_LAST_LINE,false); ChartSetInteger(0,CHART_SHOW_TRADE_LEVELS,false); ChartSetInteger(0,CHART_SHOW_GRID,false); ChartSetInteger(0,CHART_SHOW_DATE_SCALE,false); ChartSetInteger(0,CHART_SHOW_PRICE_SCALE,false); ChartSetInteger(0,CHART_SHOW_PERIOD_SEP,false); ChartSetInteger(0,CHART_SHOW_OBJECT_DESCR,false); ChartSetInteger(0,CHART_SHOW_OHLC,false); ChartSetInteger(0,CHART_SHOW_ONE_CLICK,false); ChartSetInteger(0,CHART_SHOW_VOLUMES,CHART_VOLUME_HIDE); ChartSetInteger(0,CHART_MODE,CHART_LINE); ChartSetInteger(0,CHART_QUICK_NAVIGATION,false); ChartSetInteger(0,CHART_COLOR_BACKGROUND,clrWhite); ChartSetInteger(0,CHART_COLOR_FOREGROUND,clrWhite); ChartSetInteger(0,CHART_COLOR_BID,clrWhite); ChartSetInteger(0,CHART_COLOR_ASK,clrWhite); ChartSetInteger(0,CHART_COLOR_CHART_LINE,clrWhite); //--- } //+------------------------------------------------------------------+ //| Initialize OpenCL engine | //+------------------------------------------------------------------+ bool ModelInitialize(int &cl_ctx,int &cl_prg,int &cl_krn,int &cl_mem) { //--- initializing OpenCL objects if((cl_ctx=CLContextCreate())==INVALID_HANDLE) { Print("OpenCL not found"); return(false); } //--- compile the program string build_log; if((cl_prg=CLProgramCreate(cl_ctx,cl_src,build_log))==INVALID_HANDLE) { Print(build_log); CLContextFree(cl_ctx); Print("OpenCL program create failed"); return(false); } //--- kernel if((cl_krn=CLKernelCreate(cl_prg,"Seascape"))==INVALID_HANDLE) { CLProgramFree(cl_prg); CLContextFree(cl_ctx); Print("OpenCL kernel create failed"); return(false); } //--- create buffer ExtSizeX=(uint)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); ExtSizeY=(uint)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); if((cl_mem=CLBufferCreate(cl_ctx,ExtSizeX*ExtSizeY*sizeof(uint),CL_MEM_READ_WRITE))==INVALID_HANDLE) { CLKernelFree(cl_krn); CLProgramFree(cl_prg); CLContextFree(cl_ctx); Print("OpenCL buffer create failed"); return(false); } CLSetKernelArgMem(cl_krn,1,cl_mem); //--- return(true); } //+------------------------------------------------------------------+ //| Check and resize the window | //+------------------------------------------------------------------+ bool ModelResize(int cl_ctx,int cl_krn,int cl_mem) { //--- the same size? if(ExtSizeX!=(uint)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS) || ExtSizeY!=(uint)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS)) { ExtSizeX=(uint)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); ExtSizeY=(uint)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); //--- create buffer CLBufferFree(cl_mem); if((cl_mem=CLBufferCreate(cl_ctx,ExtSizeX*ExtSizeY*sizeof(uint),CL_MEM_READ_WRITE))!=INVALID_HANDLE) { CLSetKernelArgMem(cl_krn,1,cl_mem); return(true); } } //--- no changes return(false); } //+------------------------------------------------------------------+ //| Shutdown OpenCL engine | //+------------------------------------------------------------------+ void ModelShutdown(int cl_ctx,int cl_prg,int cl_krn,int cl_mem) { //--- remove OpenCL objects CLBufferFree(cl_mem); CLKernelFree(cl_krn); CLProgramFree(cl_prg); CLContextFree(cl_ctx); //--- } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { int cl_ctx,cl_prg,cl_krn,cl_mem; //--- prepare the chart ClearChart(); //--- initializing OpenCL objects if(ModelInitialize(cl_ctx,cl_prg,cl_krn,cl_mem)) { uint buf[]; uint work[2]; uint offset[2]={0,0}; string objname="OpenCL_"+IntegerToString(ChartID()); string resname="::Seascape_"+IntegerToString(ChartID()); //--- create object and empty picture ObjectCreate(0,objname,OBJ_BITMAP_LABEL,0,0,0); ObjectSetInteger(0,objname,OBJPROP_XDISTANCE,0); ObjectSetInteger(0,objname,OBJPROP_YDISTANCE,0); ArrayResize(buf,ExtSizeX*ExtSizeY); ResourceCreate(resname,buf,ExtSizeX,ExtSizeY,0,0,ExtSizeX,COLOR_FORMAT_XRGB_NOALPHA); ObjectSetString(0,objname,OBJPROP_BMPFILE,resname); //--- render work[0]=ExtSizeX; work[1]=ExtSizeY; for(float time=0;!IsStopped();time+=0.04f) { //--- rendering the frame CLSetKernelArg(cl_krn,0,time); CLExecute(cl_krn,2,offset,work); //--- take the frame data, save in memory and draw it CLBufferRead(cl_mem,buf); ResourceCreate(resname,buf,ExtSizeX,ExtSizeY,0,0,ExtSizeX,COLOR_FORMAT_XRGB_NOALPHA); ChartRedraw(); Sleep(0); //--- output the rendering time if(ModelResize(cl_ctx,cl_krn,cl_mem)) { work[0]=ExtSizeX; work[1]=ExtSizeY; ArrayResize(buf,ExtSizeX*ExtSizeY); } } //--- remove OpenCL objects ModelShutdown(cl_ctx,cl_prg,cl_krn,cl_mem); //--- remove object ObjectDelete(0,objname); } //--- } //+------------------------------------------------------------------+