//+------------------------------------------------------------------+ //| DemoMorphMath3D.mq5 | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2000-2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- #include #include #include #include "Functions.mqh" //--- resources #define TEXTURE_CHECKER "::Textures/checker.bmp" #resource "Textures/checker.bmp" //-- input data input double Inp_Morph_Time =3.0; // Morphing time input double Inp_Freeze_Time=1.0; // Fixing on result time input int Inp_Grid_Size =150; // Grid size input color Inp_Background =clrWhite;// Background color input bool Inp_UseChess =false; // Use chess texture //+---------------------------------------------------------------------+ //| Chart constants | //+---------------------------------------------------------------------+ #define CAMERA_ANGLES_TIMEOUT 3.0f #define CAMERA_DISTANCE_TIMEOUT 3.0f #define CAMERA_DISTANCE 40.0f #define CAMERA_RETURN_STRENGTH 0.01f #define CAMERA_ANGLE_Y_DEFAULT DX_PI/6.0f #define CAMERA_ANGLE_Y_SPEED 0.3f //+------------------------------------------------------------------+ //| GenerateDataFixedSize | //+------------------------------------------------------------------+ bool NormalizeData(double &data[],double &data_min,double &data_max) { int data_size=ArraySize(data); if(data_size<1) return(false); data_min=DBL_MAX; data_max=-DBL_MAX; for(int i=0; idata[i]) data_min=data[i]; if(data_max500) m_data_size=500; //--- generate end states data GenerateDataFixedSize(m_data_size,m_data_size,(EnMathFunction)morph_id1,m_data1); NormalizeData(m_data1,m_data1_min,m_data1_max); GenerateDataFixedSize(m_data_size,m_data_size,(EnMathFunction)morph_id2,m_data2); NormalizeData(m_data2,m_data2_min,m_data2_max); //--- create mesh if(!m_surface.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),m_data1,(uint)m_data_size,(uint)m_data_size,float(m_data1_max-m_data1_min),DXVector3(-10,-5,-10),DXVector3(10,5,10),DXVector2(1.0f,1.0f),CDXSurface::SF_TWO_SIDED|CDXSurface::SF_USE_NORMALS)) { m_canvas.Destroy(); return(false); } //--- set mesh parameters m_surface.SpecularColorSet(DXColor(1.0f,1.0f,1.0f,1.0f)); if(Inp_UseChess) m_surface.TextureSet(m_canvas.DXDispatcher(),TEXTURE_CHECKER); //--- add mesh to scene m_canvas.ObjectAdd(&m_surface); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Update frame | //+------------------------------------------------------------------+ void Redraw() { //--- render 3D m_canvas.Render(DX_CLEAR_COLOR|DX_CLEAR_DEPTH,m_background_color); //--- draw text label int left=25,top=15; static int pos=left; m_canvas.FontSet("Arial",64,FW_BLACK); //--- if(m_current_morph_factorDX_PI*0.49f) m_camera_angles.x=DX_PI*0.49f; //--- UpdateCamera(); } //--- m_mouse_x_old=x; m_mouse_y_old=y; //--- m_camera_angles_timeout=CAMERA_ANGLES_TIMEOUT; } else { m_mouse_x_old=-1; m_mouse_y_old=-1; } } //+------------------------------------------------------------------+ //| Process mouse moving event | //+------------------------------------------------------------------+ void OnMouseWheel(double delta) { m_camera_distance*=1.0-delta*0.001; if(m_camera_distance>75.0) m_camera_distance=75.0; if(m_camera_distance<20.0) m_camera_distance=20.0; UpdateCamera(); m_camera_distance_timeout=CAMERA_DISTANCE_TIMEOUT; } //+------------------------------------------------------------------+ //| Process chart change event | //+------------------------------------------------------------------+ void OnChartChange(void) { //--- get current chart window size int w=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); int h=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); //--- update size everywhere it needed if(w!=m_width || h!=m_height) { m_width =w; m_height=h; m_canvas.Resize(w,h); DXContextSetSize(m_canvas.DXContext(),w,h); m_canvas.ProjectionMatrixSet((float)M_PI/6,(float)m_width/m_height,0.1f,100.0f); Redraw(); } } //+------------------------------------------------------------------+ //| Timer handler | //+------------------------------------------------------------------+ void OnTimer(void) { double current_frame=GetMicrosecondCount()/1000000.0; double deltatime=current_frame-m_last_frame; if(deltatime>0.1) deltatime=0.1; m_last_frame=current_frame; m_current_morph_factor+=deltatime; if(m_current_morph_factor>=m_morpth_time+m_freeze_time) { m_current_morph_factor=0.0; int prev_id=morph_id1; //--- save second data to first morph_id1=morph_id2; ArraySwap(m_data1,m_data2); m_data1_min=m_data2_min; m_data1_max=m_data2_max; //--- generate new second data while(morph_id2==morph_id1 || morph_id2==prev_id) { morph_id2=MathRand()%m_functions_count; } GenerateDataFixedSize(m_data_size,m_data_size,(EnMathFunction)morph_id2,m_data2); NormalizeData(m_data2,m_data2_min,m_data2_max); } //--- generate morphed mesh if(m_current_morph_factor<=m_morpth_time) UpdateMesh(); //--- m_camera_angles_timeout-=deltatime; if(m_camera_angles_timeout<0.0) { m_camera_angles.y+=(float)deltatime*CAMERA_ANGLE_Y_SPEED; m_camera_angles.x=(1.0f-CAMERA_RETURN_STRENGTH)*m_camera_angles.x+CAMERA_RETURN_STRENGTH*CAMERA_ANGLE_Y_DEFAULT; UpdateCamera(); } m_camera_distance_timeout-=deltatime; if(m_camera_distance_timeout<0.0 && m_camera_angles_timeout<0.0) { m_camera_distance=(1.0f-CAMERA_RETURN_STRENGTH)*m_camera_distance+CAMERA_RETURN_STRENGTH*CAMERA_DISTANCE; UpdateCamera(); } //--- Redraw(); } }; //--- Global window CCanvas3DWindow *ExtAppWindow=NULL; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1); ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1); //--- get current chart window size int width =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); //--- create canvas ExtAppWindow=new CCanvas3DWindow(); if(!ExtAppWindow.Create(width,height)) return(INIT_FAILED); //--- set timer EventSetMillisecondTimer(10); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy delete ExtAppWindow; //--- kill timer EventKillTimer(); //--- revert chart showing mode ChartSetInteger(0,CHART_SHOW,true); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { ExtAppWindow.OnTimer(); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- if(id==CHARTEVENT_KEYDOWN) { if(lparam==27) ExpertRemove(); } if(id==CHARTEVENT_CHART_CHANGE) ExtAppWindow.OnChartChange(); //--- process mouse moving if(id==CHARTEVENT_MOUSE_MOVE) ExtAppWindow.OnMouseMove((int)lparam,(int)dparam,(uint)sparam); if(id==CHARTEVENT_MOUSE_WHEEL) ExtAppWindow.OnMouseWheel(dparam); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+