//+------------------------------------------------------------------+
//|                                                     Seascape.mq5 |
//|                             Copyright 2000-2026, MetaQuotes Ltd. |
//|                                                     www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2026, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#resource "seascape.cl" as string ExtCL

uint ExtSizeX=640;  // Width
uint ExtSizeY=360;  // Height
//+------------------------------------------------------------------+
//| 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,ExtCL,build_log))==INVALID_HANDLE)
     {
      //--- free
      CLContextFree(cl_ctx);
      cl_ctx=INVALID_HANDLE;
      //---
      Print("OpenCL program create failed: ",build_log);
      return(false);
     }
//--- kernel
   if((cl_krn=CLKernelCreate(cl_prg,"Seascape"))==INVALID_HANDLE)
     {
      //--- free
      CLProgramFree(cl_prg);
      cl_prg=INVALID_HANDLE;

      CLContextFree(cl_ctx);
      cl_ctx=INVALID_HANDLE;
      //---
      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)
     {
      //--- free objects
      CLKernelFree(cl_krn);
      cl_krn=INVALID_HANDLE;

      CLProgramFree(cl_prg);
      cl_prg=INVALID_HANDLE;

      CLContextFree(cl_ctx);
      cl_ctx=INVALID_HANDLE;
      //---
      Print("OpenCL buffer create failed");
      return(false);
     }

   CLSetKernelArgMem(cl_krn,1,cl_mem);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| Check and resize the window                                      |
//+------------------------------------------------------------------+
bool ModelResize(const int cl_ctx,const int cl_krn,int &cl_mem)
  {
   uint width =(uint)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);
   uint height=(uint)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS);
//--- correction
   width=(width + 7) & ~7;    // align to 8
   if(width<8)
      width=8;

   if(height<8)
      height=8;
//--- the same size?
   if(ExtSizeX!=width || ExtSizeY!=height)
     {
      ExtSizeX=width;
      ExtSizeY=height;
      //--- create buffer
      if(cl_mem!=INVALID_HANDLE)
         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
   if(cl_mem!=INVALID_HANDLE)
     {
      CLBufferFree(cl_mem);
      cl_mem=INVALID_HANDLE;
     }

   if(cl_krn!=INVALID_HANDLE)
     {
      CLKernelFree(cl_krn);
      cl_krn=INVALID_HANDLE;
     }

   if(cl_prg!=INVALID_HANDLE)
     {
      CLProgramFree(cl_prg);
      cl_prg=INVALID_HANDLE;
     }

   if(cl_ctx!=INVALID_HANDLE)
     {
      CLContextFree(cl_ctx);
      cl_ctx=INVALID_HANDLE;
     }
//---
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int  cl_ctx=INVALID_HANDLE,cl_prg=INVALID_HANDLE;
   int  cl_krn=INVALID_HANDLE,cl_mem=INVALID_HANDLE;
//--- prepare the chart
   ChartSetInteger(0,CHART_SHOW,false);
   ChartRedraw();
//--- 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)
        {
         //--- check the resolution
         if(ModelResize(cl_ctx,cl_krn,cl_mem))
           {
            work[0]=ExtSizeX;
            work[1]=ExtSizeY;
            ArrayResize(buf,ExtSizeX*ExtSizeY);
           }
         //--- 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);
        }
      //--- remove OpenCL objects
      ModelShutdown(cl_ctx,cl_prg,cl_krn,cl_mem);
      //--- remove object
      ObjectDelete(0,objname);
     }
//---
   ChartSetInteger(0,CHART_SHOW,true);
  }
//+------------------------------------------------------------------+
