| //+------------------------------------------------------------------+
|
| //| Canvas3D.mqh |
|
| //| Copyright 2000-2025, MetaQuotes Ltd. |
|
| //| https://www.mql5.com |
|
| //+------------------------------------------------------------------+
|
| //#include "Canvas.mqh"
|
| #include <Canvas\Canvas.mqh>
|
| #include "DX\DXObjectBase.mqh"
|
| #include "DX\DXHandle.mqh"
|
| #include "DX\DXMath.mqh"
|
| #include "DX\DXObject.mqh"
|
| #include "DX\DXTexture.mqh"
|
| #include "DX\DXShader.mqh"
|
| #include "DX\DXUtils.mqh"
|
| #include "DX\DXDispatcher.mqh"
|
| //+------------------------------------------------------------------+
|
| //| Render flags |
|
| //+------------------------------------------------------------------+
|
| enum ENUM_DX_RENDER_FLAGS
|
| {
|
| DX_CLEAR_COLOR = 1, // clear colors buffer
|
| DX_CLEAR_DEPTH = 2 // clear z-buffer
|
| };
|
| //+------------------------------------------------------------------+
|
| //| Class CCanvas3D |
|
| //| Usage: class for render 3D graphics through DirectX |
|
| //+------------------------------------------------------------------+
|
| class CCanvas3D : public CCanvas
|
| {
|
| protected:
|
| int m_dx_context; // DX Context Handle
|
| CDXDispatcher m_dx_dispatcher; // DX resource dispatcher
|
| CDXObjectBase m_dx_objects; // DX scene objects array
|
| CDXInput* m_input_scene; // Scene input of DXInputScene type
|
| DXMatrix m_view_matrix; // View matrix
|
| DXVector3 m_view_position; // Point of view
|
| DXVector3 m_view_target; // View target point
|
| DXVector3 m_view_up_dir; // View up direction
|
| DXMatrix m_projection_matrix; // Projection matrix
|
| DXVector4 m_light_directon; // Light direction
|
| DXColor m_light_color; // Directional light color
|
| DXColor m_ambient_color; // Ambient light color
|
|
|
| public:
|
| CCanvas3D(void);
|
| ~CCanvas3D(void);
|
| //--- get DX Context Handle
|
| int DXContext(void) const { return(m_dx_context); }
|
| CDXDispatcher* DXDispatcher(void) { return(&m_dx_dispatcher); }
|
| CDXInput* InputScene(void) { return(m_input_scene); }
|
| //--- create/attach/destroy
|
| virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA) override;
|
| virtual bool Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA) override;
|
| virtual bool Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA) override;
|
| virtual void Destroy(void) override;
|
| //--- create/delete 3D Objects
|
| bool ObjectAdd(CDXObject *object);
|
| //--- render functions
|
| bool Render(uint flags,uint background_color=0);
|
| virtual bool RenderBegin(uint flags,uint background_color=0);
|
| virtual bool RenderEnd(bool redraw=false);
|
| //--- view control function
|
| void ViewMatrixGet(DXMatrix &view_matrix);
|
| void ViewMatrixSet(const DXMatrix &view_matrix);
|
| void ViewPositionSet(const DXVector3 &posiiton);
|
| void ViewRotationSet(const DXVector3 &rotation);
|
| void ViewTargetSet(const DXVector3 &target);
|
| void ViewUpDirectionSet(const DXVector3 &up_direction);
|
| //--- projection control functions
|
| void ProjectionMatrixGet(DXMatrix &projection_matrix);
|
| void ProjectionMatrixSet(float fov,float aspect_ratio,float z_near,float z_far);
|
| //--- light control functions
|
| void LightDirectionSet(const DXVector3 &light_direction);
|
| void LightDirectionGet(DXVector3 &light_direction);
|
| void LightColorSet(const DXColor &light_color);
|
| void LightColorGet(DXColor &light_color);
|
| void AmbientColorSet(const DXColor &ambient_color);
|
| void AmbientColorGet(DXColor &ambient_color);
|
| };
|
|
|
| //+------------------------------------------------------------------+
|
| //| Set view matrix |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ViewMatrixGet(DXMatrix &view_matrix)
|
| {
|
| view_matrix=m_view_matrix;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Get view matrix |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ViewMatrixSet(const DXMatrix &view_matrix)
|
| {
|
| m_view_matrix=view_matrix;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set point of view position |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ViewPositionSet(const DXVector3 &position)
|
| {
|
| //--- set position
|
| m_view_position=position;
|
| //--- update view matrix
|
| DXMatrixLookAtLH(m_view_matrix,m_view_position,m_view_target,m_view_up_dir);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set point of view position |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ViewRotationSet(const DXVector3 &rotation)
|
| {
|
| //--- get view rotation matrix
|
| DXMatrix rot;
|
| DXMatrixRotationYawPitchRoll(rot,rotation.y,rotation.x,rotation.z);
|
| //--- get direction and up vectors for this matrix
|
| m_view_target.x=0.0;
|
| m_view_target.x=0.0;
|
| m_view_target.x=1.0;
|
| DXVec3TransformCoord(m_view_target,m_view_target,rot);
|
| //--- get up vector for this matrix
|
| m_view_up_dir.x=0.0;
|
| m_view_up_dir.y=1.0;
|
| m_view_up_dir.y=0.0;
|
| DXVec3TransformCoord(m_view_up_dir,m_view_up_dir,rot);
|
| //--- calculate far target position
|
| DXVec3Scale(m_view_target,m_view_target,1000.0);
|
| DXVec3Add(m_view_target,m_view_position,m_view_target);
|
| //--- update view matrix
|
| DXMatrixLookAtLH(m_view_matrix,m_view_position,m_view_target,m_view_up_dir);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set view target point |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ViewTargetSet(const DXVector3 &target)
|
| {
|
| //--- set target
|
| m_view_target=target;
|
| //--- update view matrix
|
| DXMatrixLookAtLH(m_view_matrix,m_view_position,m_view_target,m_view_up_dir);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set view up direction |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ViewUpDirectionSet(const DXVector3 &up_direction)
|
| {
|
| //--- set up direction
|
| m_view_up_dir=up_direction;
|
| //--- update view matrix
|
| DXMatrixLookAtLH(m_view_matrix,m_view_position,m_view_target,m_view_up_dir);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Get projection matrix |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ProjectionMatrixGet(DXMatrix &projection_matrix)
|
| {
|
| projection_matrix=m_projection_matrix;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set projection matrix |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::ProjectionMatrixSet(float fov,float aspect_ratio,float z_near,float z_far)
|
| {
|
| DXMatrixPerspectiveFovLH(m_projection_matrix,fov,aspect_ratio,z_near,z_far);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set directional light direction |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::LightDirectionSet(const DXVector3 &light_direction)
|
| {
|
| float len=DXVec3Length(light_direction);
|
| m_light_directon.x=light_direction.x/len;
|
| m_light_directon.y=light_direction.y/len;
|
| m_light_directon.z=light_direction.z/len;
|
| //--- don't translate the vetor
|
| m_light_directon.w=0.0;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Get directional light direction |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::LightDirectionGet(DXVector3 &light_direction)
|
| {
|
| light_direction=DXVector3(m_light_directon);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set directional light color |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::LightColorSet(const DXColor &light_color)
|
| {
|
| m_light_color=light_color;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Get directional light color |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::LightColorGet(DXColor &light_color)
|
| {
|
| light_color=m_light_color;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Set ambient light color |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::AmbientColorSet(const DXColor &ambient_color)
|
| {
|
| m_ambient_color=ambient_color;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Get ambient light color |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::AmbientColorGet(DXColor &ambient_color)
|
| {
|
| ambient_color=m_ambient_color;
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Constructor |
|
| //+------------------------------------------------------------------+
|
| CCanvas3D::CCanvas3D(void) : m_dx_context(-1)
|
| {
|
| //--- set identity matrices
|
| DXMatrixIdentity(m_view_matrix);
|
| DXMatrixIdentity(m_projection_matrix);
|
| //--- set zero directional light
|
| m_light_directon=DXVector4(0.0);
|
| m_light_color =DXColor(0.0,0.0,0.0,0.0);
|
| //--- set full white ambient light
|
| m_ambient_color =DXColor(1.0,1.0,1.0,1.0);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Destructor |
|
| //+------------------------------------------------------------------+
|
| CCanvas3D::~CCanvas3D(void)
|
| {
|
| Destroy();
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Create dynamic resource with 3D context |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
| {
|
| //--- create 2D canvas
|
| if(!CCanvas::Create(name,width,height,clrfmt))
|
| return(false);
|
| //--- create 3D context
|
| m_dx_context=DXContextCreate(width,height);
|
| if(m_dx_context!=INVALID_HANDLE)
|
| if(m_dx_dispatcher.Create(m_dx_context))
|
| {
|
| m_input_scene=m_dx_dispatcher.InputCreate<DXInputScene>();
|
| if(m_input_scene!=NULL)
|
| {
|
| m_input_scene.AddRef();
|
| return(true);
|
| }
|
| }
|
| //---
|
| Destroy();
|
| return(false);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Remove object from chart and release DX Context |
|
| //+------------------------------------------------------------------+
|
| void CCanvas3D::Destroy(void)
|
| {
|
| //--- destroy 2D canvas
|
| CCanvas::Destroy();
|
| //--- delete all scene objects
|
| while(m_dx_objects.Next())
|
| delete m_dx_objects.Next();
|
| //--- release dx resources
|
| if(CheckPointer(m_input_scene)!=POINTER_INVALID)
|
| {
|
| m_input_scene.Release();
|
| m_input_scene=NULL;
|
| }
|
| //--- destroy DX dispatcher
|
| m_dx_dispatcher.Destroy();
|
| //--- release context
|
| if(m_dx_context!=-1)
|
| {
|
| DXRelease(m_dx_context);
|
| m_dx_context=-1;
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Attach new object with bitmap resource |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt)
|
| {
|
| //--- attach to the chart object
|
| if(!CCanvas::Attach(chart_id,objname,clrfmt))
|
| return(false);
|
| //--- create new DX Context if it does not exists
|
| if(m_dx_context==-1)
|
| {
|
| m_dx_context=DXContextCreate(m_width,m_height);
|
| return(m_dx_context!=-1);
|
| }
|
| //--- DX Context exists, resize it to the new size
|
| return(DXContextSetSize(m_dx_context,m_width,m_height));
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Attach new object without bitmap resource |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA)
|
| {
|
| //--- attach to the chart object
|
| if(!CCanvas::Attach(chart_id,objname,width,height,clrfmt))
|
| return(false);
|
| //--- create new DX Context if it does not exists
|
| if(m_dx_context==-1)
|
| {
|
| m_dx_context=DXContextCreate(m_width,m_height);
|
| return(m_dx_context!=-1);
|
| }
|
| //--- DX Context exists, resize it to the new size
|
| return(DXContextSetSize(m_dx_context,m_width,m_height));
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Rendering 3D scene |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::Render(uint flags,uint background_color)
|
| {
|
| //--- start rendering
|
| if(!RenderBegin(flags,background_color))
|
| return(false);
|
| //--- pass all non-skipped objects to render
|
| for(CDXObject *object=m_dx_objects.Next(); CheckPointer(object)!=POINTER_INVALID; object=object.Next())
|
| object.Render();
|
| //--- finish the render
|
| return(RenderEnd(false));
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Start 3D render |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::RenderBegin(uint flags,uint background_color)
|
| {
|
| //--- check resource dispatcher
|
| m_dx_dispatcher.Check();
|
| //--- clear color buffer
|
| if((flags&DX_CLEAR_COLOR)!=0)
|
| {
|
| DXVector v;
|
| v.x=GETRGBR(background_color)/255.0f;
|
| v.y=GETRGBG(background_color)/255.0f;
|
| v.z=GETRGBB(background_color)/255.0f;
|
| v.w=GETRGBA(background_color)/255.0f;
|
| if(!DXContextClearColors(m_dx_context,v))
|
| return(false);
|
| }
|
| //--- clear depth buffer
|
| if((flags&DX_CLEAR_DEPTH)!=0)
|
| if(!DXContextClearDepth(m_dx_context))
|
| return(false);
|
| //--- update scene input
|
| DXInputScene input_data;
|
| DXMatrixTranspose(input_data.view, m_view_matrix);
|
| DXMatrixTranspose(input_data.projection,m_projection_matrix);
|
| DXVec4Transform(input_data.light_direction,m_light_directon,m_view_matrix);
|
| input_data.light_color =m_light_color;
|
| input_data.ambient_color=m_ambient_color;
|
| //--- set input
|
| if(!m_input_scene.InputSet(input_data))
|
| return(false);
|
| //--- succes
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Finish 3D render |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::RenderEnd(bool redraw)
|
| {
|
| //--- finish render
|
| if(!DXContextGetColors(m_dx_context,m_pixels))
|
| return(false);
|
| //--- update canvas 2D if needed
|
| if(redraw)
|
| CCanvas::Update(redraw);
|
| //---
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Add user 3D object |
|
| //+------------------------------------------------------------------+
|
| bool CCanvas3D::ObjectAdd(CDXObject *object)
|
| {
|
| //--- add user object
|
| if(!CheckPointer(object))
|
| return(false);
|
| //---
|
| CDXObjectBase *last=&m_dx_objects;
|
|
|
| while(CheckPointer(last.Next())!=POINTER_INVALID)
|
| {
|
| if(last==object)
|
| return(false);
|
| //---
|
| last=last.Next();
|
| }
|
|
|
| object.Next(NULL);
|
| object.Prev(last);
|
| last.Next(object);
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|