From f40175dfbde791747e9e05c00b44cc87366cf4fe Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 16 Apr 2021 18:18:50 +0200 Subject: [PATCH 01/97] WIP. 3D visualization for MT5. --- 3D/Device.h | 88 ++++++++ 3D/Devices/MTDX/MTDXDevice.h | 81 +++++++ 3D/Devices/MTDX/MTDXIndexBuffer.h | 13 ++ 3D/Devices/MTDX/MTDXShader.h | 25 +++ 3D/Devices/MTDX/MTDXVertexBuffer.h | 12 ++ 3D/Frontend.h | 37 ++++ 3D/Frontends/MT5Frontend.h | 19 ++ 3D/IndexBuffer.h | 26 +++ 3D/Shader.h | 38 ++++ 3D/Vertex.h | 11 + 3D/VertexBuffer.h | 21 ++ tests/3D/Shaders/pixel.hlsl | 328 +++++++++++++++++++++++++++++ tests/3D/Shaders/vertex.hlsl | 18 ++ tests/3DTest.mq5 | 72 +++++++ 14 files changed, 789 insertions(+) create mode 100644 3D/Device.h create mode 100644 3D/Devices/MTDX/MTDXDevice.h create mode 100644 3D/Devices/MTDX/MTDXIndexBuffer.h create mode 100644 3D/Devices/MTDX/MTDXShader.h create mode 100644 3D/Devices/MTDX/MTDXVertexBuffer.h create mode 100644 3D/Frontend.h create mode 100644 3D/Frontends/MT5Frontend.h create mode 100644 3D/IndexBuffer.h create mode 100644 3D/Shader.h create mode 100644 3D/Vertex.h create mode 100644 3D/VertexBuffer.h create mode 100644 tests/3D/Shaders/pixel.hlsl create mode 100644 tests/3D/Shaders/vertex.hlsl create mode 100644 tests/3DTest.mq5 diff --git a/3D/Device.h b/3D/Device.h new file mode 100644 index 000000000..7c3925829 --- /dev/null +++ b/3D/Device.h @@ -0,0 +1,88 @@ +#include "../Refs.mqh" +#include "Frontend.h" +#include "IndexBuffer.h" +#include "Shader.h" +#include "VertexBuffer.h" + +enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; + +/** + * Graphics device. + */ +class Device : public Dynamic { + public: + bool Start(Frontend* _frontend) { return Init(_frontend); } + + Device* Begin() { + Clear(0x000000); + RenderBegin(); + return &this; + } + + Device* End() { + RenderEnd(); + return &this; + } + + Device* Stop() { + Deinit(); + return &this; + } + + Device* Clear(unsigned int _color = 0xFF000000) { + ClearBuffer(CLEAR_BUFFER_TYPE_COLOR, _color); + return &this; + } + + Device* ClearDepth() { + ClearBuffer(CLEAR_BUFFER_TYPE_DEPTH, 0); + return &this; + } + + /** + * Creates index buffer to be used by current graphics device. + */ + virtual IndexBuffer* IndexBuffer() = NULL; + + /** + * Creates vertex shader to be used by current graphics device. + */ + virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") = NULL; + + /** + * Creates pixel shader to be used by current graphics device. + */ + virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + + /** + * Creates vertex buffer to be used by current graphics device. + */ + virtual VertexBuffer* VertexBuffer() = NULL; + + protected: + /** + * Initializes graphics device. + */ + virtual bool Init(Frontend*) = NULL; + + /** + * Deinitializes graphics device. + */ + virtual bool Deinit() = NULL; + + /** + * Starts rendering loop. + */ + virtual bool RenderBegin() = NULL; + + /** + * Ends rendering loop. + */ + virtual bool RenderEnd() = NULL; + + /** + * Clears color buffer. + */ + virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color) = NULL; +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h new file mode 100644 index 000000000..6094184f1 --- /dev/null +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -0,0 +1,81 @@ +#include "../../Device.h" + +class MTDXDevice : public Device { + protected: + int context; + + public: + /** + * Initializes graphics device. + */ + bool Init(Frontend* _frontend) { + context = DXContextCreate(_frontend.Width(), _frontend.Height()); + + return true; + } + + /** + * Deinitializes graphics device. + */ + bool Deinit() { return true; } + + /** + * Starts rendering loop. + */ + virtual bool RenderBegin() { return true; } + + /** + * Ends rendering loop. + */ + virtual bool RenderEnd() { return true; } + + /** + * Returns DX context's id. + */ + int Context() { return context; } + + /** + * Clears color buffer. + */ + /** + * Clears color buffer. + */ + virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color = 0x000000) { + if (_type == CLEAR_BUFFER_TYPE_COLOR) { + DXVector _dx_color; + _dx_color.x = 1; + DXContextClearColors(context, _dx_color); + } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { + DXContextClearDepth(context); + } + } + + /** + * Creates index buffer to be used by current graphics device. + */ + IndexBuffer* IndexBuffer() { return NULL; } + + /** + * Creates vertex shader to be used by current graphics device. + */ + virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], string _entry_point = "main") { + MTDXShader* _shader = new MTDXShader(&this); + _shader.Create(SHADER_TYPE_VS, _source_code, _entry_point); + _shader.SetDataLayout(_layout); + return _shader; + } + + /** + * Creates pixel shader to be used by current graphics device. + */ + virtual Shader* PixelShader(string _source_code, string _entry_point = "main") { + MTDXShader* _shader = new MTDXShader(&this); + _shader.Create(SHADER_TYPE_PS, _source_code, _entry_point); + return _shader; + } + + /** + * Creates vertex buffer to be used by current graphics device. + */ + VertexBuffer* VertexBuffer() { return NULL; } +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h new file mode 100644 index 000000000..53109e770 --- /dev/null +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -0,0 +1,13 @@ +#include "../../IndexBuffer.h" + +class MTDXIndexBuffer : public IndexBuffer { + MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} + + /** + * Creates index buffer. + */ + virtual bool Create(void*& _data[]) { + // DXBufferCreate(((MTDXDevice*)Device()).Context(), DX_BUFFER_INDEX, &_data); + return true; + } +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h new file mode 100644 index 000000000..ccab5aae3 --- /dev/null +++ b/3D/Devices/MTDX/MTDXShader.h @@ -0,0 +1,25 @@ +#include "../../Shader.h" + +class MTDXShader : public Shader { + int handle; + + public: + MTDXShader(Device *_device) : Shader(_device) {} + + bool Create(ENUM_SHADER_TYPE _type, string _source_code, string _entry_point = "main") { + string error_text; + + handle = DXShaderCreate(((MTDXDevice *)GetDevice()).Context(), + _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, + error_text); + + return true; + } + + /** + * Sets vertex/pixel data layout to be used by shader. + */ + virtual void SetDataLayout(const ShaderVertexLayout &_layout[]) { + // DXShaderSetLayout(handle, _layout); + } +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h new file mode 100644 index 000000000..d6fe42414 --- /dev/null +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -0,0 +1,12 @@ +#include "../../VertexBuffer.h" + +class MTDXVertexBuffer : public VertexBuffer { + public: + /** + * Creates vertex buffer. + */ + virtual bool Create(void*& _data[]) { + DXBufferCreate(((MTDXDevice*)GetDevice()).Context(), DX_BUFFER_VERTEX, _data); + return true; + } +}; \ No newline at end of file diff --git a/3D/Frontend.h b/3D/Frontend.h new file mode 100644 index 000000000..6415d7c00 --- /dev/null +++ b/3D/Frontend.h @@ -0,0 +1,37 @@ +#include "../Refs.mqh" + +/** + * Represents visual target (OS window/canvas for rendering). + */ +class Frontend : public Dynamic { + public: + /** + * Initializes canvas. + */ + bool Start() { return Init(); } + + /** + * Deinitializes canvas. + */ + bool End() { return Deinit(); } + + /** + * Initializes canvas. + */ + virtual bool Init() = NULL; + + /** + * Deinitializes canvas. + */ + virtual bool Deinit() = NULL; + + /** + * Returns canvas' width. + */ + virtual int Width() = NULL; + + /** + * Returns canvas' height. + */ + virtual int Height() = NULL; +}; \ No newline at end of file diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h new file mode 100644 index 000000000..5ff154f38 --- /dev/null +++ b/3D/Frontends/MT5Frontend.h @@ -0,0 +1,19 @@ +#include "../Frontend.h" + +/** + * MetaTrader 5 chart target. + */ +class MT5Frontend : public Frontend { + virtual bool Init() { + // Hiding 2D chart. + ChartSetInteger(0, CHART_SHOW, false); + ChartRedraw(); + return true; + } + + virtual bool Deinit() { return true; } + + virtual int Width() { return (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); } + + virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } +}; \ No newline at end of file diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h new file mode 100644 index 000000000..4279991f8 --- /dev/null +++ b/3D/IndexBuffer.h @@ -0,0 +1,26 @@ +#include "../Refs.mqh" + +class Device; + +/** + * Vertices' index buffer. + */ +class IndexBuffer : public Dynamic { + WeakRef device; + + public: + /** + * Constructor. + */ + IndexBuffer(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } + + /** + * Creates index buffer. + */ + virtual bool Create(void*& _data[]) = NULL; +}; \ No newline at end of file diff --git a/3D/Shader.h b/3D/Shader.h new file mode 100644 index 000000000..e013d54c0 --- /dev/null +++ b/3D/Shader.h @@ -0,0 +1,38 @@ +#include "../Refs.mqh" + +enum ENUM_SHADER_TYPE { + SHADER_TYPE_VS, + SHADER_TYPE_PS, +}; + +class Device; + +enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; + +struct ShaderVertexLayout { + string name; + unsigned int index; + ENUM_GFX_VAR_TYPE_FLOAT type; + unsigned int num_components; + bool clamped; + unsigned int stride; + unsigned int offset; +}; + +/** + * Unified vertex/pixel shader. + */ +class Shader : public Dynamic { + WeakRef device; + + public: + /** + * Constructor. + */ + Shader(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } +}; \ No newline at end of file diff --git a/3D/Vertex.h b/3D/Vertex.h new file mode 100644 index 000000000..6561fad32 --- /dev/null +++ b/3D/Vertex.h @@ -0,0 +1,11 @@ +#include "../Refs.mqh" + +struct Vertex { + struct Position { + float x, y, z; + } position; + + struct Color { + float r, g, b, a; + } color; +}; \ No newline at end of file diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h new file mode 100644 index 000000000..36ad0b53f --- /dev/null +++ b/3D/VertexBuffer.h @@ -0,0 +1,21 @@ +#include "../Refs.mqh" + +class VertexBuffer : public Dynamic { + WeakRef device; + + public: + /** + * Constructor. + */ + VertexBuffer(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } + + /** + * Creates index buffer. + */ + virtual bool Create(void*& _data[]) = NULL; +}; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl new file mode 100644 index 000000000..9445e5732 --- /dev/null +++ b/tests/3D/Shaders/pixel.hlsl @@ -0,0 +1,328 @@ +// Remnant X +// by David Hoskins. +// Thanks to boxplorer and the folks at 'Fractalforums.com' +// HD Video:- https://www.youtube.com/watch?v=BjkK9fLXXo0 +// https://www.shadertoy.com/view/4sjSW1 + +struct PSInput + { + float4 position : SV_POSITION; + }; + +cbuffer Input + { + float2 iResolution; + float iTime; + float iDummy; + }; + +#define PI 3.14159265f +#define SCALE 2.8 +#define MINRAD2 .25 +#define scale (float4(SCALE, SCALE, SCALE, abs(SCALE)) / minRad2) + +static const float minRad2 = clamp(MINRAD2, 1.0e-9, 1.0); +static const float absScalem1 = abs(SCALE - 1.0); +static const float AbsScaleRaisedTo1mIters = pow(abs(SCALE), float(1-10)); +static const float3 surfaceColour1 = float3(.8, .0, 0.); +static const float3 surfaceColour2 = float3(.4, .4, 0.5); +static const float3 surfaceColour3 = float3(.5, 0.3, 0.00); +static const float3 fogCol = float3(0.4, 0.4, 0.4); + +static const float3 sunDir=normalize(float3(0.35,0.1,0.3)); +static const float4 sunColour=float4(1.0,0.95,0.8,0.2); + + +float2 Rand(float2 p) + { + return(float2(frac(sin(dot(p,float2(12.9898,78.233)))*6.7416516),frac(sin(dot(p,float2(58.6542,22.6546)))*6.5465145))); + } + +float2 Texture(float2 p) + { + float2 p1=Rand(floor(p*256+float2(0,0))); + float2 p2=Rand(floor(p*256+float2(0,1))); + float2 p3=Rand(floor(p*256+float2(1,0))); + float2 p4=Rand(floor(p*256+float2(1,1))); + float2 f =frac(p*256); + + return lerp(lerp(p1,p2,f.y),lerp(p3,p4,f.y),f.x); + } + +//---------------------------------------------------------------------------------------- +float Noise(in float3 x) + { + float3 p=floor(x); + float3 f=frac(x); + f=f*f*(3.0-2.0*f); + + float2 uv=(p.xy+float2(37.0,17.0)*p.z)+f.xy; + float2 rg=Rand((uv+0.5)/256.0).yx;//texture(iChannel0,(uv+0.5)/256.0,-99.0).yx; + return lerp(rg.x,rg.y,f.z); + } + +//---------------------------------------------------------------------------------------- +float Map(float3 pos) + { + + float4 p=float4(pos,1); + float4 p0=p; // p.w is the distance estimate + + for(int i = 0; i < 9; i++) + { + p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; + + float r2=dot(p.xyz,p.xyz); + p*=clamp(max(minRad2/r2,minRad2),0.0,1.0); + + // scale, translate + p=p*scale+p0; + } + return ((length(p.xyz)-absScalem1)/p.w-AbsScaleRaisedTo1mIters); + } + +//---------------------------------------------------------------------------------------- +float3 Colour(float3 pos, float sphereR) + { + float3 p=pos; + float3 p0=p; + float trap=1.0; + + for(int i = 0; i < 6; i++) + { + p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; + float r2 = dot(p.xyz,p.xyz); + p*=clamp(max(minRad2/r2,minRad2), 0.0, 1.0); + + p=p*scale.xyz+p0.xyz; + trap=min(trap,r2); + } +// |c.x|: log final distance (fractional iteration count) +// |c.y|: spherical orbit trap at (0,0,0) + float2 c=clamp(float2(0.3333*log(dot(p,p))-1.0,sqrt(trap)),0.0, 1.0); + + float t=fmod(length(pos)-iTime*1.5,16.0); + float3 surfaceColour=lerp(surfaceColour1,float3(0.4,3.0,5.0),pow(smoothstep(0.0,0.3,t)*smoothstep(0.6,.3,t),10.0)); + return lerp(lerp(surfaceColour,surfaceColour2,c.y),surfaceColour3,c.x); + } + + +//---------------------------------------------------------------------------------------- +float3 GetNormal(float3 pos, float distance) + { + distance*=0.001+.0001; + float2 eps=float2(distance,0.0); + float3 nor=float3(Map(pos+eps.xyy) - Map(pos-eps.xyy), + Map(pos+eps.yxy) - Map(pos-eps.yxy), + Map(pos+eps.yyx) - Map(pos-eps.yyx)); + return normalize(nor); + } + +//---------------------------------------------------------------------------------------- +float GetSky(float3 pos) + { + pos*=0.02; + float2 t=0.5 *Texture(pos.xy*2.1) +0.5*Texture(pos.yz*2.3-(float2)0.53) +0.5*Texture(pos.zx*1.9+(float2)0.47)+ + 0.25 *Texture(pos.xy*4.7) +0.25*Texture(pos.yz*4.1+(float2)0.71) +0.25*Texture(pos.zx*4.3+(float2)0.59)+ + 0.125*Texture(pos.xy*8.7)+0.125*Texture(pos.yz*8.6-(float2)0.69)+0.125*Texture(pos.zx*8.3+(float2)0.95); + + return(pow(t.x*t.y,0.5)); + } + +//---------------------------------------------------------------------------------------- +float BinarySubdivision(in float3 rO, in float3 rD, float2 t) + { + float halfwayT; + + for(int i = 0; i < 6; i++) + { + + halfwayT=dot(t,float2(0.5,0.5)); + float d = Map(rO + halfwayT*rD); + //if (abs(d) < 0.001) break; + t=lerp(float2(t.x,halfwayT),float2(halfwayT,t.y),step(0.0005, d)); + } + + return halfwayT; + } + +//---------------------------------------------------------------------------------------- +float2 Scene(in float3 rO, in float3 rD, in float2 fragCoord) + { + float t=.05+0.05*Texture(fragCoord.xy/256).y;//texture(iChannel0, fragCoord.xy / iChannelResolution[0].xy).y; + float3 p=float3(0.0,0.0,0.0); + float oldT=0.0; + bool hit=false; + float glow=0.0; + float2 dist; + for(int j=0; j < 100; j++) + { + if(t > 12.0) + break; + p=rO+t*rD; + + float h=Map(p); + + if(h<0.0005) + { + dist=float2(oldT,t); + hit=true; + break; + } + glow+=clamp(.05-h,0.0,.4); + oldT=t; + t+=h+t*0.001; + } + if(!hit) + t=1000.0; + else + t=BinarySubdivision(rO, rD, dist); + return float2(t,clamp(glow*.25, 0.0, 1.0)); + + } + +//---------------------------------------------------------------------------------------- +float Hash(float2 p) + { + return frac(sin(dot(p,float2(12.9898,78.233)))*33758.5453)-.5; + } + +//---------------------------------------------------------------------------------------- +float3 PostEffects(float3 rgb, float2 xy) + { +// Gamma first... + + +// Then... +#define CONTRAST 1.08 +#define SATURATION 1.5 +#define BRIGHTNESS 1.5 + float tmp=dot(float3(.2125, .7154, .0721),rgb*BRIGHTNESS); + rgb=lerp(float3(0.5,0.5,0.5),lerp(float3(tmp,tmp,tmp),rgb*BRIGHTNESS,SATURATION),CONTRAST); +// Noise... +//rgb = clamp(rgb+Hash(xy*iTime)*.1, 0.0, 1.0); +// Vignette... + rgb*=.5+0.5*pow(20.0*xy.x*xy.y*(1.0-xy.x)*(1.0-xy.y), 0.2); + + rgb=pow(rgb,float3(0.47,0.47,0.47)); + return rgb; + } + +//---------------------------------------------------------------------------------------- +float Shadow(in float3 ro, in float3 rd) + { + float res=1.0; + float t=0.05; + float h; + + for(int i = 0; i < 8; i++) + { + h=Map(ro+rd*t); + res=min(6.0*h/t,res); + t+=h; + } + return max(res, 0.0); + } + +//---------------------------------------------------------------------------------------- +float3x3 RotationMatrix(float3 axis, float angle) + { + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return float3x3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); + } + +//---------------------------------------------------------------------------------------- +float3 LightSource(float3 spotLight, float3 dir, float dis) + { + float g=0.0; + if(length(spotLight) < dis) + { + g=pow(max(dot(normalize(spotLight),dir),0.0),200.0); + } + + return(g*sunColour.rgb*sunColour.a); + } + +//---------------------------------------------------------------------------------------- +float3 CameraPath(float t) + { + float3 p=float3(-0.78+3.0*sin(2.14*t),0.05+2.5*sin(0.942*t+1.3),.05+3.5*cos(3.594*t)); + return p; + } + +//---------------------------------------------------------------------------------------- +float4 mainImage(float2 fragCoord) + { + //float m=(iMouse.x/iResolution.x)*300.0; + //gTime = iTime+m*.01 + 15.00; + float gTime=iTime*0.01; + float2 xy =fragCoord/iResolution; + float2 uv =(-1.0+2.0*xy)*float2(iResolution.x/iResolution.y,1.0); + + //return(float4(uv,0.0,1.0)); + + float3 cameraPos=CameraPath(gTime); + float3 camTar =CameraPath(gTime+.01); + + float roll=13.0*sin(gTime*.5+.4); + float3 cw=normalize(camTar-cameraPos); + + float3 cp=float3(sin(roll),cos(roll),0.0); + float3 cu=normalize(cross(cw,cp)); + + float3 cv=normalize(cross(cu,cw)); + cw=mul(cw,RotationMatrix(cv,sin(-gTime*20.0)*.7)); + float3 dir=normalize(uv.x*cu+uv.y*cv+1.3*cw); + + float3 spotLight=CameraPath(gTime+.03)+float3(sin(gTime*18.4),cos(gTime*17.98),sin(gTime*22.53))*.2; + float3 col=float3(0.0,0.0,0.0); + float3 sky=float3(0.03,.04,.05)*GetSky(dir); + float2 ret=Scene(cameraPos,dir,fragCoord); + + if(ret.x<900.0) + { + float3 p=cameraPos+ret.x*dir; + float3 nor=GetNormal(p,ret.x); + + float3 spot=spotLight-p; + float atten=length(spot); + + spot/=atten; + + float shaSpot=Shadow(p,spot); + float shaSun=Shadow(p,sunDir); + + float bri=max(dot(spot,nor),0.0)/pow(atten,1.5)*.15; + float briSun=max(dot(sunDir,nor),0.0)*.3; + + col=Colour(p,ret.x); + col=(col*bri*shaSpot)+(col*briSun*shaSun); + + float3 ref=reflect(dir,nor); + col+=pow(max(dot(spot,ref),0.0), 10.0)*2.0*shaSpot*bri; + col+=pow(max(dot(sunDir,ref),0.0),10.0)*2.0*shaSun *bri; + } + + col=lerp(sky,col,min(exp(-ret.x+1.5),1.0)); + col+=(float3)pow(abs(ret.y),2.) * float3(.02, .04, .1); + + col+=LightSource(spotLight-cameraPos,dir,ret.x); + col=PostEffects(col, xy); + + return(float4(col,1.0)); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +float4 main(PSInput input) : SV_TARGET + { + return(mainImage(input.position.xy)); + } +//+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl new file mode 100644 index 000000000..f33905108 --- /dev/null +++ b/tests/3D/Shaders/vertex.hlsl @@ -0,0 +1,18 @@ +struct VSInput + { + float4 position : POSITION; + }; + +struct PSInput + { + float4 position : SV_POSITION; + }; + +PSInput main(VSInput input) + { + PSInput output; + + output.position=(input.position); + + return(output); + } \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 new file mode 100644 index 000000000..a45a946fa --- /dev/null +++ b/tests/3DTest.mq5 @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of 3D visualization classes. + */ + +// Resources. +#resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; +#resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; + +// Includes. +#include "../3D/Frontends/MT5Frontend.h" +#include "../3D/Devices/MTDX/MTDXDevice.h" +#include "../3D/Devices/MTDX/MTDXIndexBuffer.h" +#include "../3D/Devices/MTDX/MTDXShader.h" +#include "../3D/Devices/MTDX/MTDXVertexBuffer.h" +#include "../Test.mqh" + +struct Vertex { + float position[4]; +}; + +const ShaderVertexLayout VertexLayout[1] = { + { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 } +}; + +/** + * Implements OnStart(). + */ +int OnStart() { + Ref gfx_ptr = new MTDXDevice(); + Device* gfx = gfx_ptr.Ptr(); + + gfx.Start(new MT5Frontend()); + + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); + Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + + Vertex vertices[]= {{{-1,-1,0.5,1.0}},{{-1,1,0.5,1.0}},{{1,1,0.5,1.0}},{{1,-1,0.5,1.0}}}; + + while (!IsStopped()) + { + gfx.Begin().Clear(); + + gfx.End(); + } + + + gfx.Stop(); + + return (INIT_SUCCEEDED); +} From 7e239e3bde95c081765c4e048ecfb45dfa656588 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 20 Apr 2021 19:26:21 +0200 Subject: [PATCH 02/97] WIP. Closer to 3d objects rendering. --- 3D/Device.h | 43 ++++++++++++++++-- 3D/Devices/MTDX/MTDXDevice.h | 52 +++++++++++++++++----- 3D/Devices/MTDX/MTDXIndexBuffer.h | 12 ++++- 3D/Devices/MTDX/MTDXShader.h | 36 ++++++++++++++- 3D/Devices/MTDX/MTDXVertexBuffer.h | 25 ++++++++++- 3D/Frontend.h | 12 +++++ 3D/Frontends/MT5Frontend.h | 70 +++++++++++++++++++++++++++++- 3D/Shader.h | 2 + 3D/VertexBuffer.h | 7 +-- tests/3DTest.mq5 | 59 +++++++++++++++++++++---- 10 files changed, 283 insertions(+), 35 deletions(-) diff --git a/3D/Device.h b/3D/Device.h index 7c3925829..192222206 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -10,17 +10,29 @@ enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH } * Graphics device. */ class Device : public Dynamic { +protected: + + int context; + Ref frontend; + public: - bool Start(Frontend* _frontend) { return Init(_frontend); } + + bool Start(Frontend* _frontend) { + frontend = _frontend; + return Init(_frontend); + } - Device* Begin() { - Clear(0x000000); + Device* Begin(unsigned int clear_color = 0xFF000000) { + frontend.Ptr().RenderBegin(context); + ClearDepth(); + Clear(clear_color); RenderBegin(); return &this; } Device* End() { RenderEnd(); + frontend.Ptr().RenderEnd(context); return &this; } @@ -38,6 +50,11 @@ class Device : public Dynamic { ClearBuffer(CLEAR_BUFFER_TYPE_DEPTH, 0); return &this; } + + /** + * Returns graphics device context as integer. + */ + int Context() { return context; } /** * Creates index buffer to be used by current graphics device. @@ -55,10 +72,30 @@ class Device : public Dynamic { */ virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + /** + * Creates vertex buffer to be used by current graphics device. + */ + template + VertexBuffer* VertexBuffer(T& data[]) { + VertexBuffer* _buff = VertexBuffer(); + // Unfortunately we can't make this method virtual. + if (dynamic_cast(_buff) != NULL) { + // MT5's DirectX. + Print("Filling vertex buffer via MTDXVertexBuffer"); + ((MTDXVertexBuffer*)_buff).Fill(data); + } + else { + Alert("Unsupported vertex buffer device target"); + } + return _buff; + } + /** * Creates vertex buffer to be used by current graphics device. */ virtual VertexBuffer* VertexBuffer() = NULL; + + virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; protected: /** diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 6094184f1..560c977ff 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -1,34 +1,41 @@ #include "../../Device.h" class MTDXDevice : public Device { - protected: - int context; - public: /** * Initializes graphics device. */ bool Init(Frontend* _frontend) { + Print("MTDXDevice: DXContextCreate: width = ", _frontend.Width(), ", height = ", _frontend.Height()); context = DXContextCreate(_frontend.Width(), _frontend.Height()); - + Print("LastError: ", GetLastError()); + Print("MTDXDevice: context = ", context); + _frontend.Init(); return true; } /** * Deinitializes graphics device. */ - bool Deinit() { return true; } + bool Deinit() { + DXRelease(context); + return true; + } /** * Starts rendering loop. */ - virtual bool RenderBegin() { return true; } + virtual bool RenderBegin() { + return true; + } /** * Ends rendering loop. */ - virtual bool RenderEnd() { return true; } - + virtual bool RenderEnd() { + return true; + } + /** * Returns DX context's id. */ @@ -42,11 +49,16 @@ class MTDXDevice : public Device { */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color = 0x000000) { if (_type == CLEAR_BUFFER_TYPE_COLOR) { - DXVector _dx_color; - _dx_color.x = 1; + DXVector _dx_color; + _dx_color.x = 1.0f / 255.0f * ((_color & 0x00FF0000) >> 16); + _dx_color.y = 1.0f / 255.0f * ((_color & 0x0000FF00) >> 8); + _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); + _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); + Print("LastError: ", GetLastError()); } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); + Print("LastError: ", GetLastError()); } } @@ -77,5 +89,23 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { return NULL; } + VertexBuffer* VertexBuffer() { + return new MTDXVertexBuffer(&this); + } + + virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { + _vertices.Select(); + DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + if (_indices == NULL) { + if (!DXDraw(context)) { + Print("Can't draw!"); + } + Print("DXDraw: LastError: ", GetLastError()); + } + else { + //_indices.Select(); + DXDrawIndexed(context); + } + + } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 53109e770..54cbc862e 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -2,12 +2,20 @@ class MTDXIndexBuffer : public IndexBuffer { MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} + +protected: + + int handle; /** * Creates index buffer. */ virtual bool Create(void*& _data[]) { - // DXBufferCreate(((MTDXDevice*)Device()).Context(), DX_BUFFER_INDEX, &_data); - return true; + //handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); + return handle != INVALID_HANDLE; + } + + ~MTDXIndexBuffer() { + //DXRelease() } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index ccab5aae3..fe73257f1 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -9,7 +9,7 @@ class MTDXShader : public Shader { bool Create(ENUM_SHADER_TYPE _type, string _source_code, string _entry_point = "main") { string error_text; - handle = DXShaderCreate(((MTDXDevice *)GetDevice()).Context(), + handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, error_text); @@ -20,6 +20,38 @@ class MTDXShader : public Shader { * Sets vertex/pixel data layout to be used by shader. */ virtual void SetDataLayout(const ShaderVertexLayout &_layout[]) { - // DXShaderSetLayout(handle, _layout); + // Converting generic layout into MT5 DX's one. + + DXVertexLayout _target_layout[]; + ArrayResize(_target_layout, ArraySize(_layout)); + + for (int i = 0; i < ArraySize(_layout); ++i) { + _target_layout[i].semantic_name = _layout[i].name; + _target_layout[i].semantic_index = _layout[i].index; + _target_layout[i].format = ParseFormat(_layout[i]); + } + + DXShaderSetLayout(handle, _target_layout); + Print("DXShaderSetLayout: LastError: ", GetLastError()); + } + + ENUM_DX_FORMAT ParseFormat(const ShaderVertexLayout& _layout) { + if (_layout.type == GFX_VAR_TYPE_FLOAT) { + switch (_layout.num_components) { + case 1: return DX_FORMAT_R32_FLOAT; + case 2: return DX_FORMAT_R32G32_FLOAT; + case 3: return DX_FORMAT_R32G32B32_FLOAT; + case 4: return DX_FORMAT_R32G32B32A32_FLOAT; + default: + Alert("Too many components in vertex layout!"); + } + } + + Alert("Wrong vertex layout!"); + return (ENUM_DX_FORMAT)0; + } + + virtual void Select() { + DXShaderSet(GetDevice().Context(), handle); } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index d6fe42414..afb844e15 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -1,12 +1,33 @@ #include "../../VertexBuffer.h" class MTDXVertexBuffer : public VertexBuffer { + + int handle; + public: + + MTDXVertexBuffer(Device *_device) : VertexBuffer(_device) {} + + ~MTDXVertexBuffer() { + DXRelease(handle); + } + +public: + /** * Creates vertex buffer. */ - virtual bool Create(void*& _data[]) { - DXBufferCreate(((MTDXDevice*)GetDevice()).Context(), DX_BUFFER_VERTEX, _data); + template + bool Fill(X& _data[]) { + handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_VERTEX, _data); + Print("Created vb ", handle); + Print("Fill: LastError: ", GetLastError()); return true; } + + virtual void Select() { + Print("Selecting vb ", handle); + DXBufferSet(GetDevice().Context(), handle); + Print("Select: LastError: ", GetLastError()); + } }; \ No newline at end of file diff --git a/3D/Frontend.h b/3D/Frontend.h index 6415d7c00..e0696eaa9 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -25,6 +25,18 @@ class Frontend : public Dynamic { */ virtual bool Deinit() = NULL; + /** + * Executed before render starts. + */ + virtual void RenderBegin(int context) = NULL; + + /** + * Executed after render ends. + */ + virtual void RenderEnd(int context) = NULL; + + virtual void Refresh(int context) {}; + /** * Returns canvas' width. */ diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 5ff154f38..a2c9e51a8 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -4,14 +4,82 @@ * MetaTrader 5 chart target. */ class MT5Frontend : public Frontend { + unsigned int image[]; + int last_width, last_height; + string resname; + string objname; + +public: + virtual bool Init() { // Hiding 2D chart. ChartSetInteger(0, CHART_SHOW, false); ChartRedraw(); + + Print("LastError: ", GetLastError()); + + objname = "MT5_Frontend_" + IntegerToString(ChartID()); + resname = "::MT5_Frontend" + IntegerToString(ChartID()); + ObjectCreate(0, objname, OBJ_BITMAP_LABEL, 0, 0, 0); + ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 0); + ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 0); + Print("LastError: ", GetLastError()); + + Print("LastError: ", GetLastError()); + Print("ResourceCreate: width = ", Width(), ", height = ", Height()); + ObjectSetString(ChartID(), objname, OBJPROP_BMPFILE, resname); + Print("LastError: ", GetLastError()); return true; } - virtual bool Deinit() { return true; } + virtual bool Deinit() { + ResourceFree(resname); + ObjectDelete(0, objname); + ChartSetInteger(0, CHART_SHOW, true); + return true; + } + + bool Resize() { + if (Width() == last_width && Height() == last_height) { + return false; + } + + ArrayResize(image, Width() * Height()); + Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + Print("ResourceCreate: LastError: ", GetLastError()); + + last_width = Width(); + last_height = Height(); + + return true; + } + + virtual void RenderBegin(int context) { + Print("MT5Frontend: RenderBegin()"); + Print("Image resize: width = ", Width(), ", height = ", Height()); + + if (Resize()) { + DXContextSetSize(context, Width(), Height()); + } + + Print("DXContextSetSize: LastError: ", GetLastError()); + } + + virtual void RenderEnd(int context) { + Print("MT5Frontend: RenderEnd()"); + Print("ResourceCreate: width = ", Width(), ", height = ", Height()); + Print("MT5Frontend: DXContextGetColors()"); + DXContextGetColors(context, image); + Print("DXContextGetColors: LastError: ", GetLastError()); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + Print("ResourceCreate: LastError: ", GetLastError()); + ChartRedraw(); + Sleep(1); + } + + virtual void Refresh(int context) { + } virtual int Width() { return (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); } diff --git a/3D/Shader.h b/3D/Shader.h index e013d54c0..258743293 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -35,4 +35,6 @@ class Shader : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } + + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h index 36ad0b53f..cf3f600f4 100644 --- a/3D/VertexBuffer.h +++ b/3D/VertexBuffer.h @@ -13,9 +13,6 @@ class VertexBuffer : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } - - /** - * Creates index buffer. - */ - virtual bool Create(void*& _data[]) = NULL; + + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index a45a946fa..c39d61b8f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -37,34 +37,75 @@ #include "../Test.mqh" struct Vertex { - float position[4]; + float Position[4]; + float Color[4]; }; -const ShaderVertexLayout VertexLayout[1] = { - { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 } +const ShaderVertexLayout VertexLayout[2] = { + { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 }, + { "COLOR", 1, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*4 }, }; +#define GFX_DEVICE MTDXDevice + +#ifdef __MQL__ + #define FILL_VERTEX_BUFFER(BUFFER, T, VERTICES) ((MTDXVertexBuffer*)BUFFER).Fill(VERTICES) +#endif + +int OnStart() { + return OnInit(); +} + /** * Implements OnStart(). */ -int OnStart() { - Ref gfx_ptr = new MTDXDevice(); +int OnInit() { + Ref gfx_ptr = new GFX_DEVICE(); + Print("Device initialized"); Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); + Print("Front-end initialized"); + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + //Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + + Vertex vertices[]= { + { + {-1,-1,0.5,1.0}, + {1, 0, 0, 1}, + }, + { + {-1,1,0.5,1.0}, + {0, 1, 0, 1}, + }, + { + {1,1,0.5,1.0}, + {0, 0, 1, 1}, + }, + { + {1,-1,0.5,1.0}, + {1, 0, 1, 1}, + } + }; - Vertex vertices[]= {{{-1,-1,0.5,1.0}},{{-1,1,0.5,1.0}},{{1,1,0.5,1.0}},{{1,-1,0.5,1.0}}}; + Ref _vbuff = gfx.VertexBuffer(vertices); while (!IsStopped()) { - gfx.Begin().Clear(); + if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { + break; + } + + gfx.Begin(0xFF00FF00); + + _shader_v.Ptr().Select(); + + gfx.Render(_vbuff.Ptr()); gfx.End(); } - gfx.Stop(); From 27c6290c8b24e287296fd925c97001236a271848 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 21 Apr 2021 18:06:45 +0200 Subject: [PATCH 03/97] WIP. Can't force MT5 to render any triangles :( --- 3D/Device.h | 33 ++- 3D/Devices/MTDX/MTDXDevice.h | 19 +- 3D/Devices/MTDX/MTDXIndexBuffer.h | 25 ++- 3D/Devices/MTDX/MTDXShader.h | 10 + 3D/Frontends/MT5Frontend.h | 2 +- 3D/IndexBuffer.h | 10 + tests/3D/Shaders/pixel.hlsl | 330 +----------------------------- tests/3D/Shaders/vertex.hlsl | 23 ++- tests/3DTest.mq5 | 57 +++--- 9 files changed, 130 insertions(+), 379 deletions(-) diff --git a/3D/Device.h b/3D/Device.h index 192222206..e1c57b052 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -22,7 +22,7 @@ class Device : public Dynamic { return Init(_frontend); } - Device* Begin(unsigned int clear_color = 0xFF000000) { + Device* Begin(unsigned int clear_color = 0) { frontend.Ptr().RenderBegin(context); ClearDepth(); Clear(clear_color); @@ -56,11 +56,6 @@ class Device : public Dynamic { */ int Context() { return context; } - /** - * Creates index buffer to be used by current graphics device. - */ - virtual IndexBuffer* IndexBuffer() = NULL; - /** * Creates vertex shader to be used by current graphics device. */ @@ -94,10 +89,34 @@ class Device : public Dynamic { * Creates vertex buffer to be used by current graphics device. */ virtual VertexBuffer* VertexBuffer() = NULL; - + + /** + * Creates index buffer to be used by current graphics device. + */ + virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; + + /** + * Renders vertex buffer with optional point indices. + */ virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + + /** + * Activates shader for rendering. + */ + void SetShader(Shader *_shader) { + _shader.Select(); + } + + /** + * Activates shaders for rendering. + */ + void SetShader(Shader *_shader1, Shader *_shader2) { + _shader1.Select(); + _shader2.Select(); + } protected: + /** * Initializes graphics device. */ diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 560c977ff..1777b485c 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -55,10 +55,10 @@ class MTDXDevice : public Device { _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); - Print("LastError: ", GetLastError()); + Print("DXContextClearColors: LastError: ", GetLastError()); } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); - Print("LastError: ", GetLastError()); + Print("DXContextClearDepth: LastError: ", GetLastError()); } } @@ -93,9 +93,18 @@ class MTDXDevice : public Device { return new MTDXVertexBuffer(&this); } + /** + * Creates index buffer to be used by current graphics device. + */ + virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) { + IndexBuffer* _buffer = new MTDXIndexBuffer(&this); + _buffer.Fill(_indices); + return _buffer; + } + virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { - _vertices.Select(); DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + _vertices.Select(); if (_indices == NULL) { if (!DXDraw(context)) { Print("Can't draw!"); @@ -103,9 +112,9 @@ class MTDXDevice : public Device { Print("DXDraw: LastError: ", GetLastError()); } else { - //_indices.Select(); + _indices.Select(); DXDrawIndexed(context); + Print("DXDrawIndexed: LastError: ", GetLastError()); } - } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 54cbc862e..6b305c832 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -1,6 +1,8 @@ #include "../../IndexBuffer.h" class MTDXIndexBuffer : public IndexBuffer { +public: + MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} protected: @@ -14,8 +16,27 @@ class MTDXIndexBuffer : public IndexBuffer { //handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); return handle != INVALID_HANDLE; } - + + /** + * Destructor; + */ ~MTDXIndexBuffer() { - //DXRelease() + DXRelease(handle); + } + + /** + * Fills index buffer with indices. + */ + virtual void Fill(unsigned int& _indices[]) { + handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_INDEX, _indices); + } + + /** + * Activates index buffer for rendering. + */ + virtual void Select() { + Print("Selecting indices ", handle); + DXBufferSet(GetDevice().Context(), handle); + Print("Select: LastError: ", GetLastError()); } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index fe73257f1..ebd53a41c 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -12,6 +12,8 @@ class MTDXShader : public Shader { handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, error_text); + + Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); return true; } @@ -25,14 +27,22 @@ class MTDXShader : public Shader { DXVertexLayout _target_layout[]; ArrayResize(_target_layout, ArraySize(_layout)); + Print("ArrayResize: LastError: ", GetLastError()); + for (int i = 0; i < ArraySize(_layout); ++i) { _target_layout[i].semantic_name = _layout[i].name; _target_layout[i].semantic_index = _layout[i].index; _target_layout[i].format = ParseFormat(_layout[i]); + + Print(_target_layout[i].semantic_name, "@", i, ": ", EnumToString(_target_layout[i].format)); } + + Print("before DXShaderSetLayout: LastError: ", GetLastError()); DXShaderSetLayout(handle, _target_layout); Print("DXShaderSetLayout: LastError: ", GetLastError()); + + ResetLastError(); } ENUM_DX_FORMAT ParseFormat(const ShaderVertexLayout& _layout) { diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index a2c9e51a8..5a9ea8713 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -75,7 +75,7 @@ class MT5Frontend : public Frontend { ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); Print("ResourceCreate: LastError: ", GetLastError()); ChartRedraw(); - Sleep(1); + Sleep(50); } virtual void Refresh(int context) { diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h index 4279991f8..230532002 100644 --- a/3D/IndexBuffer.h +++ b/3D/IndexBuffer.h @@ -23,4 +23,14 @@ class IndexBuffer : public Dynamic { * Creates index buffer. */ virtual bool Create(void*& _data[]) = NULL; + + /** + * Fills index buffer with indices. + */ + virtual void Fill(unsigned int& _indices[]) = NULL; + + /** + * Activates index buffer for rendering. + */ + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index 9445e5732..f985e1f0a 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,328 +1,10 @@ -// Remnant X -// by David Hoskins. -// Thanks to boxplorer and the folks at 'Fractalforums.com' -// HD Video:- https://www.youtube.com/watch?v=BjkK9fLXXo0 -// https://www.shadertoy.com/view/4sjSW1 - struct PSInput - { - float4 position : SV_POSITION; - }; - -cbuffer Input - { - float2 iResolution; - float iTime; - float iDummy; - }; - -#define PI 3.14159265f -#define SCALE 2.8 -#define MINRAD2 .25 -#define scale (float4(SCALE, SCALE, SCALE, abs(SCALE)) / minRad2) - -static const float minRad2 = clamp(MINRAD2, 1.0e-9, 1.0); -static const float absScalem1 = abs(SCALE - 1.0); -static const float AbsScaleRaisedTo1mIters = pow(abs(SCALE), float(1-10)); -static const float3 surfaceColour1 = float3(.8, .0, 0.); -static const float3 surfaceColour2 = float3(.4, .4, 0.5); -static const float3 surfaceColour3 = float3(.5, 0.3, 0.00); -static const float3 fogCol = float3(0.4, 0.4, 0.4); - -static const float3 sunDir=normalize(float3(0.35,0.1,0.3)); -static const float4 sunColour=float4(1.0,0.95,0.8,0.2); - - -float2 Rand(float2 p) - { - return(float2(frac(sin(dot(p,float2(12.9898,78.233)))*6.7416516),frac(sin(dot(p,float2(58.6542,22.6546)))*6.5465145))); - } - -float2 Texture(float2 p) - { - float2 p1=Rand(floor(p*256+float2(0,0))); - float2 p2=Rand(floor(p*256+float2(0,1))); - float2 p3=Rand(floor(p*256+float2(1,0))); - float2 p4=Rand(floor(p*256+float2(1,1))); - float2 f =frac(p*256); - - return lerp(lerp(p1,p2,f.y),lerp(p3,p4,f.y),f.x); - } - -//---------------------------------------------------------------------------------------- -float Noise(in float3 x) - { - float3 p=floor(x); - float3 f=frac(x); - f=f*f*(3.0-2.0*f); - - float2 uv=(p.xy+float2(37.0,17.0)*p.z)+f.xy; - float2 rg=Rand((uv+0.5)/256.0).yx;//texture(iChannel0,(uv+0.5)/256.0,-99.0).yx; - return lerp(rg.x,rg.y,f.z); - } - -//---------------------------------------------------------------------------------------- -float Map(float3 pos) - { - - float4 p=float4(pos,1); - float4 p0=p; // p.w is the distance estimate - - for(int i = 0; i < 9; i++) - { - p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; - - float r2=dot(p.xyz,p.xyz); - p*=clamp(max(minRad2/r2,minRad2),0.0,1.0); - - // scale, translate - p=p*scale+p0; - } - return ((length(p.xyz)-absScalem1)/p.w-AbsScaleRaisedTo1mIters); - } - -//---------------------------------------------------------------------------------------- -float3 Colour(float3 pos, float sphereR) - { - float3 p=pos; - float3 p0=p; - float trap=1.0; - - for(int i = 0; i < 6; i++) - { - p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; - float r2 = dot(p.xyz,p.xyz); - p*=clamp(max(minRad2/r2,minRad2), 0.0, 1.0); - - p=p*scale.xyz+p0.xyz; - trap=min(trap,r2); - } -// |c.x|: log final distance (fractional iteration count) -// |c.y|: spherical orbit trap at (0,0,0) - float2 c=clamp(float2(0.3333*log(dot(p,p))-1.0,sqrt(trap)),0.0, 1.0); - - float t=fmod(length(pos)-iTime*1.5,16.0); - float3 surfaceColour=lerp(surfaceColour1,float3(0.4,3.0,5.0),pow(smoothstep(0.0,0.3,t)*smoothstep(0.6,.3,t),10.0)); - return lerp(lerp(surfaceColour,surfaceColour2,c.y),surfaceColour3,c.x); - } - - -//---------------------------------------------------------------------------------------- -float3 GetNormal(float3 pos, float distance) - { - distance*=0.001+.0001; - float2 eps=float2(distance,0.0); - float3 nor=float3(Map(pos+eps.xyy) - Map(pos-eps.xyy), - Map(pos+eps.yxy) - Map(pos-eps.yxy), - Map(pos+eps.yyx) - Map(pos-eps.yyx)); - return normalize(nor); - } - -//---------------------------------------------------------------------------------------- -float GetSky(float3 pos) - { - pos*=0.02; - float2 t=0.5 *Texture(pos.xy*2.1) +0.5*Texture(pos.yz*2.3-(float2)0.53) +0.5*Texture(pos.zx*1.9+(float2)0.47)+ - 0.25 *Texture(pos.xy*4.7) +0.25*Texture(pos.yz*4.1+(float2)0.71) +0.25*Texture(pos.zx*4.3+(float2)0.59)+ - 0.125*Texture(pos.xy*8.7)+0.125*Texture(pos.yz*8.6-(float2)0.69)+0.125*Texture(pos.zx*8.3+(float2)0.95); - - return(pow(t.x*t.y,0.5)); - } - -//---------------------------------------------------------------------------------------- -float BinarySubdivision(in float3 rO, in float3 rD, float2 t) - { - float halfwayT; - - for(int i = 0; i < 6; i++) - { - - halfwayT=dot(t,float2(0.5,0.5)); - float d = Map(rO + halfwayT*rD); - //if (abs(d) < 0.001) break; - t=lerp(float2(t.x,halfwayT),float2(halfwayT,t.y),step(0.0005, d)); - } - - return halfwayT; - } - -//---------------------------------------------------------------------------------------- -float2 Scene(in float3 rO, in float3 rD, in float2 fragCoord) - { - float t=.05+0.05*Texture(fragCoord.xy/256).y;//texture(iChannel0, fragCoord.xy / iChannelResolution[0].xy).y; - float3 p=float3(0.0,0.0,0.0); - float oldT=0.0; - bool hit=false; - float glow=0.0; - float2 dist; - for(int j=0; j < 100; j++) - { - if(t > 12.0) - break; - p=rO+t*rD; - - float h=Map(p); - - if(h<0.0005) - { - dist=float2(oldT,t); - hit=true; - break; - } - glow+=clamp(.05-h,0.0,.4); - oldT=t; - t+=h+t*0.001; - } - if(!hit) - t=1000.0; - else - t=BinarySubdivision(rO, rD, dist); - return float2(t,clamp(glow*.25, 0.0, 1.0)); +{ + float4 color : COLOR0; +}; - } - -//---------------------------------------------------------------------------------------- -float Hash(float2 p) - { - return frac(sin(dot(p,float2(12.9898,78.233)))*33758.5453)-.5; - } - -//---------------------------------------------------------------------------------------- -float3 PostEffects(float3 rgb, float2 xy) - { -// Gamma first... - - -// Then... -#define CONTRAST 1.08 -#define SATURATION 1.5 -#define BRIGHTNESS 1.5 - float tmp=dot(float3(.2125, .7154, .0721),rgb*BRIGHTNESS); - rgb=lerp(float3(0.5,0.5,0.5),lerp(float3(tmp,tmp,tmp),rgb*BRIGHTNESS,SATURATION),CONTRAST); -// Noise... -//rgb = clamp(rgb+Hash(xy*iTime)*.1, 0.0, 1.0); -// Vignette... - rgb*=.5+0.5*pow(20.0*xy.x*xy.y*(1.0-xy.x)*(1.0-xy.y), 0.2); - - rgb=pow(rgb,float3(0.47,0.47,0.47)); - return rgb; - } - -//---------------------------------------------------------------------------------------- -float Shadow(in float3 ro, in float3 rd) - { - float res=1.0; - float t=0.05; - float h; - - for(int i = 0; i < 8; i++) - { - h=Map(ro+rd*t); - res=min(6.0*h/t,res); - t+=h; - } - return max(res, 0.0); - } - -//---------------------------------------------------------------------------------------- -float3x3 RotationMatrix(float3 axis, float angle) - { - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return float3x3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); - } - -//---------------------------------------------------------------------------------------- -float3 LightSource(float3 spotLight, float3 dir, float dis) - { - float g=0.0; - if(length(spotLight) < dis) - { - g=pow(max(dot(normalize(spotLight),dir),0.0),200.0); - } - - return(g*sunColour.rgb*sunColour.a); - } - -//---------------------------------------------------------------------------------------- -float3 CameraPath(float t) - { - float3 p=float3(-0.78+3.0*sin(2.14*t),0.05+2.5*sin(0.942*t+1.3),.05+3.5*cos(3.594*t)); - return p; - } - -//---------------------------------------------------------------------------------------- -float4 mainImage(float2 fragCoord) - { - //float m=(iMouse.x/iResolution.x)*300.0; - //gTime = iTime+m*.01 + 15.00; - float gTime=iTime*0.01; - float2 xy =fragCoord/iResolution; - float2 uv =(-1.0+2.0*xy)*float2(iResolution.x/iResolution.y,1.0); - - //return(float4(uv,0.0,1.0)); - - float3 cameraPos=CameraPath(gTime); - float3 camTar =CameraPath(gTime+.01); - - float roll=13.0*sin(gTime*.5+.4); - float3 cw=normalize(camTar-cameraPos); - - float3 cp=float3(sin(roll),cos(roll),0.0); - float3 cu=normalize(cross(cw,cp)); - - float3 cv=normalize(cross(cu,cw)); - cw=mul(cw,RotationMatrix(cv,sin(-gTime*20.0)*.7)); - float3 dir=normalize(uv.x*cu+uv.y*cv+1.3*cw); - - float3 spotLight=CameraPath(gTime+.03)+float3(sin(gTime*18.4),cos(gTime*17.98),sin(gTime*22.53))*.2; - float3 col=float3(0.0,0.0,0.0); - float3 sky=float3(0.03,.04,.05)*GetSky(dir); - float2 ret=Scene(cameraPos,dir,fragCoord); - - if(ret.x<900.0) - { - float3 p=cameraPos+ret.x*dir; - float3 nor=GetNormal(p,ret.x); - - float3 spot=spotLight-p; - float atten=length(spot); - - spot/=atten; - - float shaSpot=Shadow(p,spot); - float shaSun=Shadow(p,sunDir); - - float bri=max(dot(spot,nor),0.0)/pow(atten,1.5)*.15; - float briSun=max(dot(sunDir,nor),0.0)*.3; - - col=Colour(p,ret.x); - col=(col*bri*shaSpot)+(col*briSun*shaSun); - - float3 ref=reflect(dir,nor); - col+=pow(max(dot(spot,ref),0.0), 10.0)*2.0*shaSpot*bri; - col+=pow(max(dot(sunDir,ref),0.0),10.0)*2.0*shaSun *bri; - } - - col=lerp(sky,col,min(exp(-ret.x+1.5),1.0)); - col+=(float3)pow(abs(ret.y),2.) * float3(.02, .04, .1); - - col+=LightSource(spotLight-cameraPos,dir,ret.x); - col=PostEffects(col, xy); - - return(float4(col,1.0)); - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ float4 main(PSInput input) : SV_TARGET - { - return(mainImage(input.position.xy)); - } +{ + return float4(1.0f, 0.0f, 1.0f, 1.0f); +} //+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index f33905108..5d31ddf5f 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -1,18 +1,19 @@ struct VSInput - { - float4 position : POSITION; - }; - +{ + float3 position : POSITION; + float4 color : COLOR0; +}; + struct PSInput - { - float4 position : SV_POSITION; - }; +{ + float4 color : COLOR0; +}; PSInput main(VSInput input) - { +{ PSInput output; - output.position=(input.position); + output.color = float4(1, 1, 1, 1); - return(output); - } \ No newline at end of file + return output; +} \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index c39d61b8f..f66e9571b 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -36,61 +36,60 @@ #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../Test.mqh" +int OnStart() { + return OnInit(); +} + struct Vertex { - float Position[4]; + float Position[3]; float Color[4]; }; -const ShaderVertexLayout VertexLayout[2] = { - { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 }, - { "COLOR", 1, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*4 }, +const ShaderVertexLayout VertexLayout[] = { + { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0 }, + { "COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*3 }, }; -#define GFX_DEVICE MTDXDevice - -#ifdef __MQL__ - #define FILL_VERTEX_BUFFER(BUFFER, T, VERTICES) ((MTDXVertexBuffer*)BUFFER).Fill(VERTICES) -#endif - -int OnStart() { - return OnInit(); -} - /** * Implements OnStart(). */ int OnInit() { - Ref gfx_ptr = new GFX_DEVICE(); - Print("Device initialized"); - Device* gfx = gfx_ptr.Ptr(); + Ref gfx_ptr = new MTDXDevice(); + Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); - Print("Front-end initialized"); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); - //Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref _shader_p = gfx.PixelShader(ShaderSourcePS); Vertex vertices[]= { { - {-1,-1,0.5,1.0}, - {1, 0, 0, 1}, + {-0.5, -0.5, 0.5}, + { 1, 0, 0, 1}, }, { - {-1,1,0.5,1.0}, + {-0.5, 0.5, 0.5}, {0, 1, 0, 1}, }, { - {1,1,0.5,1.0}, + {0.5, 0.5, 0.5}, {0, 0, 1, 1}, }, { - {1,-1,0.5,1.0}, - {1, 0, 1, 1}, + {0.5, -0.5, 0.5}, + {0, 0, 1, 1}, } }; + + unsigned int indices[] = { + 0, 1, 2, + 2, 3, 0 + }; Ref _vbuff = gfx.VertexBuffer(vertices); + Ref _ibuff = gfx.IndexBuffer(indices); + + unsigned int _rand_color = rand() * 1256; while (!IsStopped()) { @@ -98,11 +97,11 @@ int OnInit() { break; } - gfx.Begin(0xFF00FF00); + gfx.Begin(_rand_color); - _shader_v.Ptr().Select(); + gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); - gfx.Render(_vbuff.Ptr()); + gfx.Render(_vbuff.Ptr(), _ibuff.Ptr()); gfx.End(); } From 0dab24b25e1f932742103b9f6ce7509afd53eba0 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 22 Apr 2021 20:29:41 +0200 Subject: [PATCH 04/97] Finally made MT5 to render object and move camera in 3D --- 3D/Device.h | 1 + 3D/Devices/MTDX/MTDXShader.h | 31 +++++++++++++++++++++++--- 3D/Frontends/MT5Frontend.h | 2 +- 3D/Shader.h | 14 ++++++++++++ tests/3D/Shaders/pixel.hlsl | 5 +++-- tests/3D/Shaders/vertex.hlsl | 22 +++++++++++++++---- tests/3DTest.mq5 | 42 +++++++++++++++++++++++++++--------- 7 files changed, 97 insertions(+), 20 deletions(-) diff --git a/3D/Device.h b/3D/Device.h index e1c57b052..71a952b58 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -3,6 +3,7 @@ #include "IndexBuffer.h" #include "Shader.h" #include "VertexBuffer.h" +#include "Math.h" enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index ebd53a41c..957ec122a 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -2,6 +2,7 @@ class MTDXShader : public Shader { int handle; + int cbuffer_handle; public: MTDXShader(Device *_device) : Shader(_device) {} @@ -14,6 +15,8 @@ class MTDXShader : public Shader { error_text); Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); + + cbuffer_handle = 0; return true; } @@ -29,17 +32,22 @@ class MTDXShader : public Shader { Print("ArrayResize: LastError: ", GetLastError()); - for (int i = 0; i < ArraySize(_layout); ++i) { + int i; + + for (i = 0; i < ArraySize(_layout); ++i) { _target_layout[i].semantic_name = _layout[i].name; _target_layout[i].semantic_index = _layout[i].index; _target_layout[i].format = ParseFormat(_layout[i]); - - Print(_target_layout[i].semantic_name, "@", i, ": ", EnumToString(_target_layout[i].format)); } + for (i = 0; i < ArraySize(_target_layout); ++i) { + Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", EnumToString(_target_layout[i].format)); + } + Print("before DXShaderSetLayout: LastError: ", GetLastError()); DXShaderSetLayout(handle, _target_layout); + Print("DXShaderSetLayout: LastError: ", GetLastError()); ResetLastError(); @@ -61,6 +69,23 @@ class MTDXShader : public Shader { return (ENUM_DX_FORMAT)0; } + template + void SetCBuffer(const X& data) { + if (cbuffer_handle == 0) { + cbuffer_handle = DXInputCreate(GetDevice().Context(), sizeof(X)); + Print("DXInputCreate: LastError: ", GetLastError()); + + int _input_handles[1]; + _input_handles[0] = cbuffer_handle; + + DXShaderInputsSet(handle, _input_handles); + Print("DXShaderInputsSet: LastError: ", GetLastError()); + } + + DXInputSet(cbuffer_handle, data); + Print("DXInputSet: LastError: ", GetLastError()); + } + virtual void Select() { DXShaderSet(GetDevice().Context(), handle); } diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 5a9ea8713..ef0caa6d2 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -75,7 +75,7 @@ class MT5Frontend : public Frontend { ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); Print("ResourceCreate: LastError: ", GetLastError()); ChartRedraw(); - Sleep(50); + Sleep(5); } virtual void Refresh(int context) { diff --git a/3D/Shader.h b/3D/Shader.h index 258743293..1ef91bd65 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -6,6 +6,7 @@ enum ENUM_SHADER_TYPE { }; class Device; +class MTDXShader; enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; @@ -36,5 +37,18 @@ class Shader : public Dynamic { */ Device* GetDevice() { return device.Ptr(); } + template + void SetCBuffer(const X& data) { + // Unfortunately we can't make this method virtual. + if (dynamic_cast(&this) != NULL) { + // MT5's DirectX. + Print("Setting CBuffer data for MT5"); + ((MTDXShader*)&this).SetCBuffer(data); + } + else { + Alert("Unsupported cbuffer device target"); + } + } + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index f985e1f0a..e4ddb278c 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,10 +1,11 @@ struct PSInput { - float4 color : COLOR0; + float4 position : SV_POSITION; + float4 color : COLOR; }; float4 main(PSInput input) : SV_TARGET { - return float4(1.0f, 0.0f, 1.0f, 1.0f); + return input.color; } //+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index 5d31ddf5f..6a92c8b1b 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -1,19 +1,33 @@ +cbuffer CBuffer +{ + matrix world; + matrix view; + matrix proj; +}; + struct VSInput { - float3 position : POSITION; - float4 color : COLOR0; + float4 position : POSITION; + float4 color : COLOR; }; struct PSInput { - float4 color : COLOR0; + float4 position : SV_POSITION; + float4 color : COLOR; }; PSInput main(VSInput input) { PSInput output; - output.color = float4(1, 1, 1, 1); + input.position.w = 1.0f; + output.position = mul(world, input.position); + output.position = mul(view, output.position); + output.position = mul(proj, output.position); + + output.color = input.color; + return output; } \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index f66e9571b..9a20bfd27 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -50,12 +50,19 @@ const ShaderVertexLayout VertexLayout[] = { { "COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*3 }, }; +struct PSCBuffer +{ + DXMatrix world; + DXMatrix view; + DXMatrix proj; +}; + /** * Implements OnStart(). */ int OnInit() { Ref gfx_ptr = new MTDXDevice(); - Device* gfx = gfx_ptr.Ptr(); + Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); @@ -64,20 +71,20 @@ int OnInit() { Vertex vertices[]= { { - {-0.5, -0.5, 0.5}, - { 1, 0, 0, 1}, + {-0.5, -0.5, 0.0}, + { 1.0, 0.0, 0.0, 1.0}, }, { - {-0.5, 0.5, 0.5}, - {0, 1, 0, 1}, + {-0.5, 0.5, 0.0}, + { 0.0, 0.1, 0.0, 1.0}, }, { - {0.5, 0.5, 0.5}, - {0, 0, 1, 1}, + { 0.5, 0.5, 0.0}, + { 0.0, 0.0, 1.0, 1.0}, }, { - {0.5, -0.5, 0.5}, - {0, 0, 1, 1}, + { 0.5, -0.5, 0.0}, + { 0.5, 0.5, 1.0, 1.0}, } }; @@ -99,8 +106,23 @@ int OnInit() { gfx.Begin(_rand_color); - gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); + PSCBuffer psCBuffer; + + DXMatrixIdentity(psCBuffer.world); + DXMatrixIdentity(psCBuffer.view); + DXMatrixIdentity(psCBuffer.proj); + DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI/6, 1.5f, 0.1f, 100.0f); + DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -5), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); + DXMatrix rotate; + static float x = 0; x += 0.1f; + DXMatrixRotationZ(rotate, x); + + DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate); + + + _shader_v.Ptr().SetCBuffer(psCBuffer); + gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); gfx.Render(_vbuff.Ptr(), _ibuff.Ptr()); gfx.End(); From 7a75dfa97e57f956bd7a994fa65190e9d7b57883 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 27 Apr 2021 17:16:39 +0200 Subject: [PATCH 05/97] Working 3D renderer with Cube class and custom `Mesh`-es support. --- 3D/Cube.h | 67 + 3D/Device.h | 86 +- 3D/Devices/MTDX/MTDXDevice.h | 53 +- 3D/Devices/MTDX/MTDXIndexBuffer.h | 47 +- 3D/Devices/MTDX/MTDXShader.h | 109 +- 3D/Devices/MTDX/MTDXVertexBuffer.h | 44 +- 3D/Face.h | 92 + 3D/Frontend.h | 31 +- 3D/Frontends/MT5Frontend.h | 91 +- 3D/IndexBuffer.h | 31 +- 3D/Math.h | 3211 ++++++++++++++++++++++++++++ 3D/Mesh.h | 172 ++ 3D/Shader.h | 45 +- 3D/VertexBuffer.h | 30 +- Dict.mqh | 14 + DictObject.mqh | 14 + DictStruct.mqh | 14 + Util.h | 46 + tests/3DTest.mq5 | 115 +- 19 files changed, 4138 insertions(+), 174 deletions(-) create mode 100644 3D/Cube.h create mode 100644 3D/Face.h create mode 100644 3D/Math.h create mode 100644 3D/Mesh.h create mode 100644 Util.h diff --git a/3D/Cube.h b/3D/Cube.h new file mode 100644 index 000000000..b11194300 --- /dev/null +++ b/3D/Cube.h @@ -0,0 +1,67 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Cube mesh. + */ + +#include "Face.h" +#include "Mesh.h" + +/** + * Cube mesh. + */ +template +class Cube : public Mesh { + public: + Cube(float x = 0.0f, float y = 0.0f, float z = 0.0f, float size_x = 1.0f, float size_y = 1.0f, float size_z = 1.0f) { + float half_x = size_x / 2; + float half_y = size_y / 2; + float half_z = size_z / 2; + + Face f1(x - half_x, y - half_y, z - half_z, x - half_x, y + half_y, z - half_z, x + half_x, y + half_y, + z - half_z, x + half_x, y - half_y, z - half_z); + + Face f2(x + half_x, y - half_y, z + half_z, x + half_x, y + half_y, z + half_z, x - half_x, y + half_y, + z + half_z, x - half_x, y - half_y, z + half_z); + + Face f3(x - half_x, y - half_y, z + half_z, x - half_x, y + half_y, z + half_z, x - half_x, y + half_y, + z - half_z, x - half_x, y - half_y, z - half_z); + + Face f4(x + half_x, y - half_y, z - half_z, x + half_x, y + half_y, z - half_z, x + half_x, y + half_y, + z + half_z, x + half_x, y - half_y, z + half_z); + + Face f5(x - half_x, y - half_y, z + half_z, x - half_x, y - half_y, z - half_z, x + half_x, y - half_y, + z - half_z, x + half_x, y - half_y, z + half_z); + + Face f6(x - half_x, y + half_y, z - half_z, x - half_x, y + half_y, z + half_z, x + half_x, y + half_y, + z + half_z, x + half_x, y + half_y, z - half_z); + + AddFace(f1); + AddFace(f2); + AddFace(f3); + AddFace(f4); + AddFace(f5); + AddFace(f6); + } +}; \ No newline at end of file diff --git a/3D/Device.h b/3D/Device.h index 71a952b58..e9b259e0a 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -1,9 +1,37 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics device. + */ + #include "../Refs.mqh" #include "Frontend.h" #include "IndexBuffer.h" +#include "Math.h" +#include "Mesh.h" #include "Shader.h" #include "VertexBuffer.h" -#include "Math.h" enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; @@ -11,18 +39,22 @@ enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH } * Graphics device. */ class Device : public Dynamic { -protected: - + protected: int context; - Ref frontend; - + Ref frontend; + public: - + /** + * Initializes graphics device. + */ bool Start(Frontend* _frontend) { frontend = _frontend; return Init(_frontend); } + /** + * Begins render loop. + */ Device* Begin(unsigned int clear_color = 0) { frontend.Ptr().RenderBegin(context); ClearDepth(); @@ -31,27 +63,39 @@ class Device : public Dynamic { return &this; } + /** + * Ends render loop. + */ Device* End() { RenderEnd(); frontend.Ptr().RenderEnd(context); return &this; } + /** + * Deinitializes graphics device. + */ Device* Stop() { Deinit(); return &this; } + /** + * Clears scene's color buffer. + */ Device* Clear(unsigned int _color = 0xFF000000) { ClearBuffer(CLEAR_BUFFER_TYPE_COLOR, _color); return &this; } + /** + * Begins scene's depth buffer. + */ Device* ClearDepth() { ClearBuffer(CLEAR_BUFFER_TYPE_DEPTH, 0); return &this; } - + /** * Returns graphics device context as integer. */ @@ -71,7 +115,7 @@ class Device : public Dynamic { /** * Creates vertex buffer to be used by current graphics device. */ - template + template VertexBuffer* VertexBuffer(T& data[]) { VertexBuffer* _buff = VertexBuffer(); // Unfortunately we can't make this method virtual. @@ -79,8 +123,7 @@ class Device : public Dynamic { // MT5's DirectX. Print("Filling vertex buffer via MTDXVertexBuffer"); ((MTDXVertexBuffer*)_buff).Fill(data); - } - else { + } else { Alert("Unsupported vertex buffer device target"); } return _buff; @@ -95,29 +138,38 @@ class Device : public Dynamic { * Creates index buffer to be used by current graphics device. */ virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; - + /** * Renders vertex buffer with optional point indices. */ virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; - + /** - * Activates shader for rendering. + * Renders given mesh. */ - void SetShader(Shader *_shader) { - _shader.Select(); + template + void Render(Mesh* _mesh) { + Print("Rendering mesh"); + VertexBuffer* _vertices; + IndexBuffer* _indices; + _mesh.GetBuffers(&this, _vertices, _indices); + Render(_vertices, _indices); } + /** + * Activates shader for rendering. + */ + void SetShader(Shader* _shader) { _shader.Select(); } + /** * Activates shaders for rendering. */ - void SetShader(Shader *_shader1, Shader *_shader2) { + void SetShader(Shader* _shader1, Shader* _shader2) { _shader1.Select(); _shader2.Select(); } protected: - /** * Initializes graphics device. */ diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 1777b485c..5794160c2 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -1,3 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted graphics device. + */ + #include "../../Device.h" class MTDXDevice : public Device { @@ -25,17 +52,13 @@ class MTDXDevice : public Device { /** * Starts rendering loop. */ - virtual bool RenderBegin() { - return true; - } + virtual bool RenderBegin() { return true; } /** * Ends rendering loop. */ - virtual bool RenderEnd() { - return true; - } - + virtual bool RenderEnd() { return true; } + /** * Returns DX context's id. */ @@ -49,7 +72,7 @@ class MTDXDevice : public Device { */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color = 0x000000) { if (_type == CLEAR_BUFFER_TYPE_COLOR) { - DXVector _dx_color; + DXVector _dx_color; _dx_color.x = 1.0f / 255.0f * ((_color & 0x00FF0000) >> 16); _dx_color.y = 1.0f / 255.0f * ((_color & 0x0000FF00) >> 8); _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); @@ -89,10 +112,8 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { - return new MTDXVertexBuffer(&this); - } - + VertexBuffer* VertexBuffer() { return new MTDXVertexBuffer(&this); } + /** * Creates index buffer to be used by current graphics device. */ @@ -101,7 +122,10 @@ class MTDXDevice : public Device { _buffer.Fill(_indices); return _buffer; } - + + /** + * + */ virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _vertices.Select(); @@ -110,8 +134,7 @@ class MTDXDevice : public Device { Print("Can't draw!"); } Print("DXDraw: LastError: ", GetLastError()); - } - else { + } else { _indices.Select(); DXDrawIndexed(context); Print("DXDrawIndexed: LastError: ", GetLastError()); diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 6b305c832..ae6d6ff3c 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -1,36 +1,59 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted graphics device's index buffer. + */ + #include "../../IndexBuffer.h" class MTDXIndexBuffer : public IndexBuffer { -public: - + public: MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} - -protected: - + + protected: int handle; /** * Creates index buffer. */ virtual bool Create(void*& _data[]) { - //handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); + // handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); return handle != INVALID_HANDLE; } /** * Destructor; - */ - ~MTDXIndexBuffer() { - DXRelease(handle); - } - + */ + ~MTDXIndexBuffer() { DXRelease(handle); } + /** * Fills index buffer with indices. */ virtual void Fill(unsigned int& _indices[]) { handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_INDEX, _indices); } - + /** * Activates index buffer for rendering. */ diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index 957ec122a..1fcf90a68 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -1,21 +1,56 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted unversal graphics shader. + */ + #include "../../Shader.h" class MTDXShader : public Shader { + // DX context handle. int handle; + + // DX C-Buffer handle. int cbuffer_handle; public: - MTDXShader(Device *_device) : Shader(_device) {} + /** + * Constructor. + */ + MTDXShader(Device* _device) : Shader(_device) {} + /** + * Creates a shader. + */ bool Create(ENUM_SHADER_TYPE _type, string _source_code, string _entry_point = "main") { string error_text; - handle = DXShaderCreate(GetDevice().Context(), - _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, - error_text); - + handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, + _source_code, _entry_point, error_text); + Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); - + cbuffer_handle = 0; return true; @@ -24,42 +59,50 @@ class MTDXShader : public Shader { /** * Sets vertex/pixel data layout to be used by shader. */ - virtual void SetDataLayout(const ShaderVertexLayout &_layout[]) { + virtual void SetDataLayout(const ShaderVertexLayout& _layout[]) { // Converting generic layout into MT5 DX's one. - - DXVertexLayout _target_layout[]; + + DXVertexLayout _target_layout[]; ArrayResize(_target_layout, ArraySize(_layout)); - + Print("ArrayResize: LastError: ", GetLastError()); - + int i; - + for (i = 0; i < ArraySize(_layout); ++i) { _target_layout[i].semantic_name = _layout[i].name; _target_layout[i].semantic_index = _layout[i].index; _target_layout[i].format = ParseFormat(_layout[i]); } - + for (i = 0; i < ArraySize(_target_layout); ++i) { - Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", EnumToString(_target_layout[i].format)); + Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", + EnumToString(_target_layout[i].format)); } - + Print("before DXShaderSetLayout: LastError: ", GetLastError()); - + DXShaderSetLayout(handle, _target_layout); - + Print("DXShaderSetLayout: LastError: ", GetLastError()); - + ResetLastError(); } - + + /** + * Converts vertex layout's item into required DX's color format. + */ ENUM_DX_FORMAT ParseFormat(const ShaderVertexLayout& _layout) { if (_layout.type == GFX_VAR_TYPE_FLOAT) { switch (_layout.num_components) { - case 1: return DX_FORMAT_R32_FLOAT; - case 2: return DX_FORMAT_R32G32_FLOAT; - case 3: return DX_FORMAT_R32G32B32_FLOAT; - case 4: return DX_FORMAT_R32G32B32A32_FLOAT; + case 1: + return DX_FORMAT_R32_FLOAT; + case 2: + return DX_FORMAT_R32G32_FLOAT; + case 3: + return DX_FORMAT_R32G32B32_FLOAT; + case 4: + return DX_FORMAT_R32G32B32A32_FLOAT; default: Alert("Too many components in vertex layout!"); } @@ -68,8 +111,11 @@ class MTDXShader : public Shader { Alert("Wrong vertex layout!"); return (ENUM_DX_FORMAT)0; } - - template + + /** + * Sets custom input buffer for shader. + */ + template void SetCBuffer(const X& data) { if (cbuffer_handle == 0) { cbuffer_handle = DXInputCreate(GetDevice().Context(), sizeof(X)); @@ -77,16 +123,17 @@ class MTDXShader : public Shader { int _input_handles[1]; _input_handles[0] = cbuffer_handle; - + DXShaderInputsSet(handle, _input_handles); Print("DXShaderInputsSet: LastError: ", GetLastError()); } - + DXInputSet(cbuffer_handle, data); Print("DXInputSet: LastError: ", GetLastError()); } - - virtual void Select() { - DXShaderSet(GetDevice().Context(), handle); - } + + /** + * Selectes shader to be used by graphics device for rendering. + */ + virtual void Select() { DXShaderSet(GetDevice().Context(), handle); } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index afb844e15..c3cf7fdda 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -1,30 +1,54 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted graphics vertex buffer. + */ + #include "../../VertexBuffer.h" class MTDXVertexBuffer : public VertexBuffer { - int handle; public: - - MTDXVertexBuffer(Device *_device) : VertexBuffer(_device) {} - + MTDXVertexBuffer(Device* _device) : VertexBuffer(_device) {} + ~MTDXVertexBuffer() { - DXRelease(handle); + // DXRelease(handle); } - -public: - + + public: /** * Creates vertex buffer. */ - template + template bool Fill(X& _data[]) { handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_VERTEX, _data); Print("Created vb ", handle); Print("Fill: LastError: ", GetLastError()); return true; } - + virtual void Select() { Print("Selecting vb ", handle); DXBufferSet(GetDevice().Context(), handle); diff --git a/3D/Face.h b/3D/Face.h new file mode 100644 index 000000000..c8a8ee9c9 --- /dev/null +++ b/3D/Face.h @@ -0,0 +1,92 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics face object. + */ + +#include "Math.h" + +// Face flags. +enum ENUM_FACE_FLAGS { FACE_FLAGS_NONE, FACE_FLAGS_TRIANGLE, FACE_FLAGS_QUAD }; + +// Face (3 or 4 vertices). +template +struct Face { + // Flags. + ENUM_FACE_FLAGS flags; + + // 3 or 4 points. + T points[4]; + + /** + * Constructor. + */ + Face() { flags = FACE_FLAGS_NONE; } + + /** + * Copy constructor. + */ + Face(const Face& r) { + flags = r.flags; + for (int p = 0; p < 4; ++p) { + points[p] = r.points[p]; + } + } + + /** + * Constructor. + */ + Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) { + flags = FACE_FLAGS_TRIANGLE; + points[0].Position[0] = x1; + points[0].Position[1] = y1; + points[0].Position[2] = z1; + points[1].Position[0] = x2; + points[1].Position[1] = y2; + points[1].Position[2] = z2; + points[2].Position[0] = x3; + points[2].Position[1] = y3; + points[2].Position[2] = z3; + } + + /** + * Constructor. + */ + Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, + float z4) { + flags = FACE_FLAGS_QUAD; + points[0].Position[0] = x1; + points[0].Position[1] = y1; + points[0].Position[2] = z1; + points[1].Position[0] = x2; + points[1].Position[1] = y2; + points[1].Position[2] = z2; + points[2].Position[0] = x3; + points[2].Position[1] = y3; + points[2].Position[2] = z3; + points[3].Position[0] = x4; + points[3].Position[1] = y4; + points[3].Position[2] = z4; + } +}; \ No newline at end of file diff --git a/3D/Frontend.h b/3D/Frontend.h index e0696eaa9..6edbec4bf 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -1,3 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics front-end (display buffer target). + */ + #include "../Refs.mqh" /** @@ -29,13 +56,11 @@ class Frontend : public Dynamic { * Executed before render starts. */ virtual void RenderBegin(int context) = NULL; - + /** * Executed after render ends. */ virtual void RenderEnd(int context) = NULL; - - virtual void Refresh(int context) {}; /** * Returns canvas' width. diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index ef0caa6d2..3d75592ec 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -1,30 +1,66 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MT5 graphics front-end (display buffer target). + */ + #include "../Frontend.h" /** * MetaTrader 5 chart target. */ class MT5Frontend : public Frontend { + // Target image pixel buffer. unsigned int image[]; + + // Previous size of the window. int last_width, last_height; + + // Target image's resource name. string resname; + + // Target image's object name. string objname; - -public: - + + public: + /** + * Initializes canvas. + */ virtual bool Init() { // Hiding 2D chart. ChartSetInteger(0, CHART_SHOW, false); ChartRedraw(); - + Print("LastError: ", GetLastError()); - + objname = "MT5_Frontend_" + IntegerToString(ChartID()); - resname = "::MT5_Frontend" + IntegerToString(ChartID()); + resname = "::MT5_Frontend" + IntegerToString(ChartID()); ObjectCreate(0, objname, OBJ_BITMAP_LABEL, 0, 0, 0); ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 0); ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 0); Print("LastError: ", GetLastError()); - + Print("LastError: ", GetLastError()); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); ObjectSetString(ChartID(), objname, OBJPROP_BMPFILE, resname); @@ -32,40 +68,52 @@ class MT5Frontend : public Frontend { return true; } + /** + * Deinitializes canvas. + */ virtual bool Deinit() { ResourceFree(resname); ObjectDelete(0, objname); ChartSetInteger(0, CHART_SHOW, true); return true; } - + + /** + * Resizes target image buffer if needed. + */ bool Resize() { if (Width() == last_width && Height() == last_height) { return false; } - + ArrayResize(image, Width() * Height()); Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); - ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); Print("ResourceCreate: LastError: ", GetLastError()); - + last_width = Width(); - last_height = Height(); - + last_height = Height(); + return true; } - + + /** + * Executed before render starts. + */ virtual void RenderBegin(int context) { Print("MT5Frontend: RenderBegin()"); Print("Image resize: width = ", Width(), ", height = ", Height()); if (Resize()) { DXContextSetSize(context, Width(), Height()); - } - + } + Print("DXContextSetSize: LastError: ", GetLastError()); } - + + /** + * Executed after render ends. + */ virtual void RenderEnd(int context) { Print("MT5Frontend: RenderEnd()"); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); @@ -77,11 +125,14 @@ class MT5Frontend : public Frontend { ChartRedraw(); Sleep(5); } - - virtual void Refresh(int context) { - } + /** + * Returns canvas' width. + */ virtual int Width() { return (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); } + /** + * Returns canvas' height. + */ virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } }; \ No newline at end of file diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h index 230532002..fef406675 100644 --- a/3D/IndexBuffer.h +++ b/3D/IndexBuffer.h @@ -1,3 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics index buffer. + */ + #include "../Refs.mqh" class Device; @@ -23,12 +50,12 @@ class IndexBuffer : public Dynamic { * Creates index buffer. */ virtual bool Create(void*& _data[]) = NULL; - + /** * Fills index buffer with indices. */ virtual void Fill(unsigned int& _indices[]) = NULL; - + /** * Activates index buffer for rendering. */ diff --git a/3D/Math.h b/3D/Math.h new file mode 100644 index 000000000..f4ca30204 --- /dev/null +++ b/3D/Math.h @@ -0,0 +1,3211 @@ +//+------------------------------------------------------------------+ +//| DXMath.mqh | +//| Copyright 2019,MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2019,MetaQuotes Software Corp." +#property link "https://www.mql5.com" +//+------------------------------------------------------------------+ +//| DirectX Math Routines | +//+------------------------------------------------------------------+ +//| Ported from C++ code of ReactOS, written by David Adam | +//| and Tony Wasserka | +//| | +//| https://doxygen.reactos.org/de/d57/ | +//| dll_2directx_2wine_2d3dx9__36_2math_8c_source.html | +//| | +//| Copyright (C) 2007 David Adam | +//| Copyright (C) 2007 Tony Wasserka | +//+------------------------------------------------------------------+ +#define DX_PI 3.1415926535897932384626f +#define DX_PI_DIV2 1.5707963267948966192313f +#define DX_PI_DIV3 1.0471975511965977461542f +#define DX_PI_DIV4 0.7853981633974483096156f +#define DX_PI_DIV6 0.5235987755982988730771f +#define DX_PI_MUL2 6.2831853071795864769253f +#define DXSH_MINORDER 2 +#define DXSH_MAXORDER 6 +//+------------------------------------------------------------------+ +//| Preliminary declarations | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| DXColor | +//+------------------------------------------------------------------+ +struct DXColor; +struct DXPlane; +struct DXVector2; +struct DXVector3; +struct DXVector4; +struct DXMatrix; +struct DXQuaternion; +struct DViewport; +//+------------------------------------------------------------------+ +//| DXColor | +//+------------------------------------------------------------------+ +struct DXColor { + float r; + float g; + float b; + float a; + //--- constructors + DXColor(void) { + r = 0.0; + g = 0.0; + b = 0.0; + a = 1.0; + } + DXColor(float red, float green, float blue, float alpha) { + r = red; + g = green; + b = blue; + a = alpha; + } + DXColor(const DXVector4 &v) { + r = v.x; + g = v.y; + b = v.z; + a = v.w; + } + DXColor(const DXVector3 &v) { + r = v.x; + g = v.y; + b = v.z; + a = 1.0; + } +}; +//+------------------------------------------------------------------+ +//| DXPlane | +//+------------------------------------------------------------------+ +struct DXPlane { + float a; + float b; + float c; + float d; +}; +//+------------------------------------------------------------------+ +//| DXVector2 | +//+------------------------------------------------------------------+ +struct DXVector2 { + float x; + float y; + //--- constructors + DXVector2(void) { + x = 0.0; + y = 0.0; + } + DXVector2(float v) { + x = v; + y = v; + } + DXVector2(float vx, float vy) { + x = vx; + y = vy; + } + DXVector2(const DXVector3 &v) { + x = v.x; + y = v.y; + } + DXVector2(const DXVector4 &v) { + x = v.x; + y = v.y; + } +}; +//+------------------------------------------------------------------+ +//| DXVector3 | +//+------------------------------------------------------------------+ +struct DXVector3 { + float x; + float y; + float z; + //--- constructors + DXVector3(void) { + x = 0.0; + y = 0.0; + z = 0.0; + } + DXVector3(float v) { + x = v; + y = v; + z = v; + } + DXVector3(float vx, float vy, float vz) { + x = vx; + y = vy; + z = vz; + } + DXVector3(const DXVector2 &v) { + x = v.x; + y = v.y; + z = 0.0; + } + DXVector3(const DXVector4 &v) { + x = v.x; + y = v.y; + z = v.z; + } +}; +//+------------------------------------------------------------------+ +//| DXVector4 | +//+------------------------------------------------------------------+ +struct DXVector4 { + float x; + float y; + float z; + float w; + //--- constructors + DXVector4(void) { + x = 0.0; + y = 0.0; + z = 0.0; + w = 1.0; + } + DXVector4(float v) { + x = v; + y = v; + z = v; + w = v; + } + DXVector4(float vx, float vy, float vz, float vw) { + x = vx; + y = vy; + z = vz; + w = vw; + } + DXVector4(const DXVector2 &v) { + x = v.x; + y = v.y; + z = 0.0; + w = 1.0; + } + DXVector4(const DXVector3 &v) { + x = v.x; + y = v.y; + z = v.z; + w = 1.0; + } +}; +//+------------------------------------------------------------------+ +//| DXMatrix | +//+------------------------------------------------------------------+ +struct DXMatrix { + float m[4][4]; +}; +//+------------------------------------------------------------------+ +//| DXQuaternion | +//+------------------------------------------------------------------+ +struct DXQuaternion { + float x; + float y; + float z; + float w; +}; +//+------------------------------------------------------------------+ +//| DViewport | +//+------------------------------------------------------------------+ +struct DViewport { + ulong x; + ulong y; + ulong width; + ulong height; + float minz; + float maxz; +}; + +/* +//--- DXColor functions +void DXColorAdd(DXColor &pout,const DXColor &pc1,const DXColor &pc2); +void DXColorAdjustContrast(DXColor &pout,const DXColor &pc,float s); +void DXColorAdjustSaturation(DXColor &pout,const DXColor &pc,float s); +void DXColorLerp(DXColor &pout,const DXColor &pc1,const DXColor &pc2,float s); +void DXColorModulate(DXColor &pout,const DXColor &pc1,const DXColor &pc2); +void DXColorNegative(DXColor &pout,const DXColor &pc); +void DXColorScale(DXColor &pout,const DXColor &pc,float s); +void DXColorSubtract(DXColor &pout,const DXColor &pc1,const DXColor &pc2); +float DXFresnelTerm(float costheta,float refractionindex); + +//--- DXVector2 functions +void DXVec2Add(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2BaryCentric(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2,const DXVector2 &pv3,float f,float g); +void DXVec2CatmullRom(DXVector2 &pout,const DXVector2 &pv0,const DXVector2 &pv1,const DXVector2 &pv2,const DXVector2 +&pv3,float s); float DXVec2CCW(const DXVector2 &pv1,const DXVector2 &pv2); float DXVec2Dot(const DXVector2 &pv1,const +DXVector2 &pv2); void DXVec2Hermite(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pt1,const DXVector2 +&pv2,const DXVector2 &pt2,float s); float DXVec2Length(const DXVector2 &v); float DXVec2LengthSq(const DXVector2 &v); +void DXVec2Lerp(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2,float s); +void DXVec2Maximize(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2Minimize(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2Normalize(DXVector2 &pout,const DXVector2 &pv); +void DXVec2Scale(DXVector2 &pout,const DXVector2 &pv,float s); +void DXVec2Subtract(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2Transform(DXVector4 &pout,const DXVector2 &pv,const DXMatrix &pm); +void DXVec2TransformCoord(DXVector2 &pout,const DXVector2 &pv,const DXMatrix &pm); +void DXVec2TransformNormal(DXVector2 &pout,const DXVector2 &pv,const DXMatrix &pm); + +//--- DXVector3 functions +void DXVec3Add(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); +void DXVec3BaryCentric(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 &pv3,float f,float g); +void DXVec3CatmullRom(DXVector3 &pout,const DXVector3 &pv0,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 +&pv3,float s); void DXVec3Cross(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); float DXVec3Dot(const +DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Hermite(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 +&pt1,const DXVector3 &pv2,const DXVector3 &pt2,float s); float DXVec3Length(const DXVector3 &pv); float +DXVec3LengthSq(const DXVector3 &pv); void DXVec3Lerp(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2,float +s); void DXVec3Maximize(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Minimize(DXVector3 +&pout,const DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Normalize(DXVector3 &pout,const DXVector3 &pv); void +DXVec3Project(DXVector3 &pout,const DXVector3 &pv,const DViewport &pviewport,const DXMatrix &pprojection,const DXMatrix +&pview,const DXMatrix &pworld); void DXVec3Scale(DXVector3 &pout,const DXVector3 &pv,float s); void +DXVec3Subtract(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Transform(DXVector4 &pout,const +DXVector3 &pv,const DXMatrix &pm); void DXVec3TransformCoord(DXVector3 &pout,const DXVector3 &pv,const DXMatrix &pm); +void DXVec3TransformNormal(DXVector3 &pout,const DXVector3 &pv,const DXMatrix &pm); +void DXVec3Unproject(DXVector3 &out,const DXVector3 &v,const DViewport &viewport,const DXMatrix &projection,const +DXMatrix &view,const DXMatrix &world); + +//--- DXVector4 vector functions +void DXVec4Add(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2); +void DXVec4BaryCentric(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2,const DXVector4 &pv3,float f,float g); +void DXVec4CatmullRom(DXVector4 &pout,const DXVector4 &pv0,const DXVector4 &pv1,const DXVector4 &pv2,const DXVector4 +&pv3,float s); void DXVec4Cross(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2,const DXVector4 &pv3); float +DXVec4Dot(const DXVector4 &pv1,const DXVector4 &pv2); void DXVec4Hermite(DXVector4 &pout,const DXVector4 &pv1,const +DXVector4 &pt1,const DXVector4 &pv2,const DXVector4 &pt2,float s); float DXVec4Length(const DXVector4 &pv); float +DXVec4LengthSq(const DXVector4 &pv); void DXVec4Lerp(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2,float +s); void DXVec4Maximize(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2); void DXVec4Minimize(DXVector4 +&pout,const DXVector4 &pv1,const DXVector4 &pv2); void DXVec4Normalize(DXVector4 &pout,const DXVector4 &pv); void +DXVec4Scale(DXVector4 &pout,const DXVector4 &pv,float s); void DXVec4Subtract(DXVector4 &pout,const DXVector4 +&pv1,const DXVector4 &pv2); void DXVec4Transform(DXVector4 &pout,const DXVector4 &pv,const DXMatrix &pm); + +//---DXQuaternion functions +void DXQuaternionBaryCentric(DXQuaternion &pout,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3,float f,float g); +void DXQuaternionConjugate(DXQuaternion &pout,const DXQuaternion &pq); +float DXQuaternionDot(DXQuaternion &a,DXQuaternion &b); +void DXQuaternionExp(DXQuaternion &out,const DXQuaternion &q); +void DXQuaternionIdentity(DXQuaternion &out); +bool DXQuaternionIsIdentity(DXQuaternion &pq); +float DXQuaternionLength(const DXQuaternion &pq); +float DXQuaternionLengthSq(const DXQuaternion &pq); +void DXQuaternionInverse(DXQuaternion &pout,const DXQuaternion &pq); +void DXQuaternionLn(DXQuaternion &out,const DXQuaternion &q); +void DXQuaternionMultiply(DXQuaternion &pout,const DXQuaternion &pq1,const DXQuaternion &pq2); +void DXQuaternionNormalize(DXQuaternion &out,const DXQuaternion &q); +void DXQuaternionRotationAxis(DXQuaternion &out,const DXVector3 &v,float angle); +void DXQuaternionRotationMatrix(DXQuaternion &out,const DXMatrix &m); +void DXQuaternionRotationYawPitchRoll(DXQuaternion &out,float yaw,float pitch,float roll); +void DXQuaternionSlerp(DXQuaternion &out,DXQuaternion &q1,DXQuaternion &q2,float t); +void DXQuaternionSquad(DXQuaternion &pout,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3,DXQuaternion &pq4,float +t); void DXQuaternionSquadSetup(DXQuaternion &paout,DXQuaternion &pbout,DXQuaternion &pcout,DXQuaternion +&pq0,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3); void DXQuaternionToAxisAngle(const DXQuaternion +&pq,DXVector3 &paxis,float &pangle); DXQuaternion add_diff(const DXQuaternion &q1,const DXQuaternion &q2,const float +add); + +//--- DXMatrix functions +void DXMatrixIdentity(DXMatrix &out); +bool DXMatrixIsIdentity(DXMatrix &pm); +void DXMatrixAffineTransformation(DXMatrix &out,float scaling,const DXVector3 &rotationcenter,const DXQuaternion +&rotation,const DXVector3 &translation); void DXMatrixAffineTransformation2D(DXMatrix &out,float scaling,const +DXVector2 &rotationcenter,float rotation,const DXVector2 &translation); int DXMatrixDecompose(DXVector3 +&poutscale,DXQuaternion &poutrotation,DXVector3 &pouttranslation,const DXMatrix &pm); float DXMatrixDeterminant(const +DXMatrix &pm); void DXMatrixInverse(DXMatrix &pout,float &pdeterminant,const DXMatrix &pm); void +DXMatrixLookAtLH(DXMatrix &out,const DXVector3 &eye,const DXVector3 &at,const DXVector3 &up); void +DXMatrixLookAtRH(DXMatrix &out,const DXVector3 &eye,const DXVector3 &at,const DXVector3 &up); void +DXMatrixMultiply(DXMatrix &pout,const DXMatrix &pm1,const DXMatrix &pm2); void DXMatrixMultiplyTranspose(DXMatrix +&pout,const DXMatrix &pm1,const DXMatrix &pm2); void DXMatrixOrthoLH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixOrthoOffCenterLH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixOrthoOffCenterRH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixOrthoRH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixPerspectiveFovLH(DXMatrix &pout,float fovy,float aspect,float zn,float zf); +void DXMatrixPerspectiveFovRH(DXMatrix &pout,float fovy,float aspect,float zn,float zf); +void DXMatrixPerspectiveLH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixPerspectiveRH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixReflect(DXMatrix &pout,const DXPlane &pplane); +void DXMatrixRotationAxis(DXMatrix &out,const DXVector3 &v,float angle); +void DXMatrixRotationQuaternion(DXMatrix &pout,const DXQuaternion &pq); +void DXMatrixRotationX(DXMatrix &pout,float angle); +void DXMatrixRotationY(DXMatrix &pout,float angle); +void DXMatrixRotationYawPitchRoll(DXMatrix &out,float yaw,float pitch,float roll); +void DXMatrixRotationZ(DXMatrix &pout,float angle); +void DXMatrixScaling(DXMatrix &pout,float sx,float sy,float sz); +void DXMatrixShadow(DXMatrix &pout,const DXVector4 &plight,const DXPlane &pplane); +void DXMatrixTransformation(DXMatrix &pout,const DXVector3 &pscalingcenter,const DXQuaternion &pscalingrotation,const +DXVector3 &pscaling,const DXVector3 &protationcenter,const DXQuaternion &protation,const DXVector3 &ptranslation); void +DXMatrixTransformation2D(DXMatrix &pout,const DXVector2 &pscalingcenter,float scalingrotation,const DXVector2 +&pscaling,const DXVector2 &protationcenter,float rotation,const DXVector2 &ptranslation); void +DXMatrixTranslation(DXMatrix &pout,float x,float y,float z); void DXMatrixTranspose(DXMatrix &pout,const DXMatrix &pm); + +//--- DXPlane functions | +float DXPlaneDot(const DXPlane &p1,const DXVector4 &p2); +float DXPlaneDotCoord(const DXPlane &pp,const DXVector4 &pv); +float DXPlaneDotNormal(const DXPlane &pp,const DXVector4 &pv); +void DXPlaneFromPointNormal(DXPlane &pout,const DXVector3 &pvpoint,const DXVector3 &pvnormal); +void DXPlaneFromPoints(DXPlane &pout,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 &pv3); +void DXPlaneIntersectLine(DXVector3 &pout,const DXPlane &pp,const DXVector3 &pv1,const DXVector3 &pv2); +void DXPlaneNormalize(DXPlane &out,const DXPlane &p); +void DXPlaneScale(DXPlane &pout,const DXPlane &p,float s); +void DXPlaneTransform(DXPlane &pout,const DXPlane &pplane,const DXMatrix &pm); + +//---- spherical harmonic functions +void DXSHAdd(float &out[],int order,const float &a[],const float &b[]); +float DXSHDot(int order,const float &a[],const float &b[]); +int DXSHEvalConeLight(int order,const DXVector3 &dir,float radius,float Rintensity,float Gintensity,float +Bintensity,float &rout[],float &gout[],float &bout[]); void DXSHEvalDirection(float &out[],int order,const DXVector3 +&dir); int DXSHEvalDirectionalLight(int order,const DXVector3 &dir,float Rintensity,float Gintensity,float +Bintensity,float &rout[],float &gout[],float &bout[]); int DXSHEvalHemisphereLight(int order,const DXVector3 +&dir,DXColor &top,DXColor &bottom,float &rout[],float &gout[],float &bout[]); int DXSHEvalSphericalLight(int +order,const DXVector3 &dir,float radius,float Rintensity,float Gintensity,float Bintensity,float &rout[],float +&gout[],float &bout[]); void DXSHMultiply2(float &out[],const float &a[],const float &b[]); void DXSHMultiply3(float +&out[],const float &a[],const float &b[]); void DXSHMultiply4(float &out[],const float &a[],const float &b[]); void +DXSHRotate(float &out[],int order,const DXMatrix &matrix,const float &in[]); void DXSHRotateZ(float &out[],int +order,float angle,const float &in[]); void DXSHScale(float &out[],int order,const float &a[],const float scale); + +//--- scalar functions +float DXScalarLerp(const float val1,const float val2,float s) +float DXScalarBiasScale(const float val,const float bias,const float scale) +*/ + +//+------------------------------------------------------------------+ +//| Adds two color values together to create a new color value. | +//+------------------------------------------------------------------+ +void DXColorAdd(DXColor &pout, const DXColor &pc1, const DXColor &pc2) { + pout.r = pc1.r + pc2.r; + pout.g = pc1.g + pc2.g; + pout.b = pc1.b + pc2.b; + pout.a = pc1.a + pc2.a; +} +//+------------------------------------------------------------------+ +//| Adjusts the contrast value of a color. | +//+------------------------------------------------------------------+ +//| The input alpha channel is copied, unmodified, | +//| to the output alpha channel. | +//| | +//| This function interpolates the red,green,and blue color | +//| components of a DXColor structure between fifty percent gray | +//| and a specified contrast value,as shown in the following example.| +//| | +//| pout.r = 0.5f + s*(pc.r - 0.5f); | +//| | +//| If s is greater than 0 and less than 1,the contrast is decreased.| +//| If s is greater than 1, the contrast is increased. | +//+------------------------------------------------------------------+ +void DXColorAdjustContrast(DXColor &pout, const DXColor &pc, float s) { + pout.r = 0.5f + s * (pc.r - 0.5f); + pout.g = 0.5f + s * (pc.g - 0.5f); + pout.b = 0.5f + s * (pc.b - 0.5f); + pout.a = pc.a; +} +//+------------------------------------------------------------------+ +//| Adjusts the saturation value of a color. | +//+------------------------------------------------------------------+ +//| The input alpha channel is copied, unmodified, | +//| to the output alpha channel. | +//| | +//| This function interpolates the red, green, and blue color | +//| components of a DXColor structure between an unsaturated color | +//| and a color, as shown in the following example. | +//| | +//| Approximate values for each component's contribution to | +//| luminance. Based upon the NTSC standard described in | +//| ITU-R Recommendation BT.709. | +//| float grey = pc.r*0.2125f + pc.g*0.7154f + pc.b*0.0721f; | +//| | +//| pout.r = grey + s*(pc.r - grey); | +//| If s is greater than 0 and less than 1, the saturation is | +//| decreased. If s is greater than 1, the saturation is increased. | +//| | +//| The grayscale color is computed as: | +//| r = g = b = 0.2125*r + 0.7154*g + 0.0721*b | +//+------------------------------------------------------------------+ +void DXColorAdjustSaturation(DXColor &pout, const DXColor &pc, float s) { + float grey = pc.r * 0.2125f + pc.g * 0.7154f + pc.b * 0.0721f; + pout.r = grey + s * (pc.r - grey); + pout.g = grey + s * (pc.g - grey); + pout.b = grey + s * (pc.b - grey); + pout.a = pc.a; +} +//+------------------------------------------------------------------+ +//| Uses linear interpolation to create a color value. | +//+------------------------------------------------------------------+ +//| This function interpolates the red, green, blue, and alpha | +//| components of a DXColor structure between two colors, as shown | +//| in the following example. | +//| | +//| pout.r = pC1.r + s * (pC2.r - pC1.r); | +//| | +//| If you are linearly interpolating between the colors A and B, | +//| and s is 0, the resulting color is A. | +//| If s is 1, the resulting color is color B. | +//+------------------------------------------------------------------+ +void DXColorLerp(DXColor &pout, const DXColor &pc1, const DXColor &pc2, float s) { + pout.r = (1 - s) * pc1.r + s * pc2.r; + pout.g = (1 - s) * pc1.g + s * pc2.g; + pout.b = (1 - s) * pc1.b + s * pc2.b; + pout.a = (1 - s) * pc1.a + s * pc2.a; +} +//+------------------------------------------------------------------+ +//| Blends two colors. | +//+------------------------------------------------------------------+ +//| This function blends together two colors by multiplying matching | +//| color components, as shown in the following example. | +//| pout.r = pC1.r * pC2.r; | +//+------------------------------------------------------------------+ +void DXColorModulate(DXColor &pout, const DXColor &pc1, const DXColor &pc2) { + pout.r = pc1.r * pc2.r; + pout.g = pc1.g * pc2.g; + pout.b = pc1.b * pc2.b; + pout.a = pc1.a * pc2.a; +} +//+------------------------------------------------------------------+ +//| Creates the negative color value of a color value. | +//+------------------------------------------------------------------+ +//| The input alpha channel is copied, unmodified, to the output | +//| alpha channel. | +//| This function returns the negative color value by subtracting 1.0| +//| from the color components of the DXColor structure, | +//| as shown in the following example. | +//| pout.r = 1.0f - pc.r; | +//+------------------------------------------------------------------+ +void DXColorNegative(DXColor &pout, const DXColor &pc) { + pout.r = 1.0f - pc.r; + pout.g = 1.0f - pc.g; + pout.b = 1.0f - pc.b; + pout.a = pc.a; +} +//+------------------------------------------------------------------+ +//| Scales a color value. | +//+------------------------------------------------------------------+ +//| This function computes the scaled color value by multiplying | +//| the color components of the DXColor structure by the specified | +//| scale factor, as shown in the following example. | +//| pOut.r = pC.r*s; | +//+------------------------------------------------------------------+ +void DXColorScale(DXColor &pout, const DXColor &pc, float s) { + pout.r = s * pc.r; + pout.g = s * pc.g; + pout.b = s * pc.b; + pout.a = s * pc.a; +} +//+------------------------------------------------------------------+ +//| Subtracts two color values to create a new color value. | +//+------------------------------------------------------------------+ +void DXColorSubtract(DXColor &pout, const DXColor &pc1, const DXColor &pc2) { + pout.r = pc1.r - pc2.r; + pout.g = pc1.g - pc2.g; + pout.b = pc1.b - pc2.b; + pout.a = pc1.a - pc2.a; +} +//+------------------------------------------------------------------+ +//| Calculate the Fresnel term. | +//+------------------------------------------------------------------+ +//| To find the Fresnel term (F): | +//| If A is angle of incidence and B is the angle of refraction, | +//| then | +//| F = 0.5*[tan2(A - B)/tan2(A + B) + sin2(A - B)/sin2(A + B)] | +//| = 0.5*sin2(A - B)/sin2(A + B)*[cos2(A + B)/cos2(A - B) + 1] | +//| | +//| Let r = sina(A)/sin(B) (the relative refractive index) | +//| Let c = cos(A) | +//| Let g = (r2 + c2 - 1)1/2 | +//| | +//| Then,expanding using the trig identities and simplifying, | +//| you get: | +//| F = 0.5*(g + c)2/(g - c)2*([c(g + c)-1]2/[c(g - c) + 1]2 + 1) | +//+------------------------------------------------------------------+ +float DXFresnelTerm(float costheta, float refractionindex) { + float g = (float)sqrt(refractionindex * refractionindex + costheta * costheta - 1.0f); + float a = g + costheta; + float d = g - costheta; + float result = (costheta * a - 1.0f) * (costheta * a - 1.0f) / ((costheta * d + 1.0f) * (costheta * d + 1.0f)) + 1.0f; + result *= 0.5f * d * d / (a * a); + //--- + return (result); +} +//+------------------------------------------------------------------+ +//| Adds two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Add(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = pv1.x + pv2.x; + pout.y = pv1.y + pv2.y; +} +//+------------------------------------------------------------------+ +//| Returns a point in Barycentric coordinates, | +//| using the specified 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2BaryCentric(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2, const DXVector2 &pv3, float f, + float g) { + pout.x = (1.0f - f - g) * (pv1.x) + f * (pv2.x) + g * (pv3.x); + pout.y = (1.0f - f - g) * (pv1.y) + f * (pv2.y) + g * (pv3.y); +} +//+------------------------------------------------------------------+ +//| Performs a Catmull-Rom interpolation, | +//| using the specified 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2CatmullRom(DXVector2 &pout, const DXVector2 &pv0, const DXVector2 &pv1, const DXVector2 &pv2, + const DXVector2 &pv3, float s) { + pout.x = 0.5f * (2.0f * pv1.x + (pv2.x - pv0.x) * s + (2.0f * pv0.x - 5.0f * pv1.x + 4.0f * pv2.x - pv3.x) * s * s + + (pv3.x - 3.0f * pv2.x + 3.0f * pv1.x - pv0.x) * s * s * s); + pout.y = 0.5f * (2.0f * pv1.y + (pv2.y - pv0.y) * s + (2.0f * pv0.y - 5.0f * pv1.y + 4.0f * pv2.y - pv3.y) * s * s + + (pv3.y - 3.0f * pv2.y + 3.0f * pv1.y - pv0.y) * s * s * s); +} +//+------------------------------------------------------------------+ +//| Returns the z-component by taking the cross product | +//| of two 2D vectors. | +//+------------------------------------------------------------------+ +float DXVec2CCW(const DXVector2 &pv1, const DXVector2 &pv2) { return (pv1.x * pv2.y - pv1.y * pv2.x); } +//+------------------------------------------------------------------+ +//| Determines the dot product of two 2D vectors. | +//+------------------------------------------------------------------+ +float DXVec2Dot(const DXVector2 &pv1, const DXVector2 &pv2) { return (pv1.x * pv2.x + pv1.y * pv2.y); } +//+------------------------------------------------------------------+ +//| Performs a Hermite spline interpolation, | +//| using the specified 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Hermite(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pt1, const DXVector2 &pv2, + const DXVector2 &pt2, float s) { + //--- prepare coefficients + float h1 = 2.0f * s * s * s - 3.0f * s * s + 1.0f; + float h2 = s * s * s - 2.0f * s * s + s; + float h3 = -2.0f * s * s * s + 3.0f * s * s; + float h4 = s * s * s - s * s; + //--- calculate interpolated point + pout.x = h1 * pv1.x + h2 * pt1.x + h3 * pv2.x + h4 * pt2.x; + pout.y = h1 * pv1.y + h2 * pt1.y + h3 * pv2.y + h4 * pt2.y; +} +//+------------------------------------------------------------------+ +//| Returns the length of a 2D vector. | +//+------------------------------------------------------------------+ +float DXVec2Length(const DXVector2 &v) { return ((float)sqrt(v.x * v.x + v.y * v.y)); } +//+------------------------------------------------------------------+ +//| Returns the square of the length of a 2D vector. | +//+------------------------------------------------------------------+ +float DXVec2LengthSq(const DXVector2 &v) { return ((float)(v.x * v.x + v.y * v.y)); } +//+------------------------------------------------------------------+ +//| Performs a linear interpolation between two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Lerp(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2, float s) { + pout.x = (1.0f - s) * pv1.x + s * pv2.x; + pout.y = (1.0f - s) * pv1.y + s * pv2.y; +} +//+------------------------------------------------------------------+ +//| Returns a 2D vector that is made up of the largest components | +//| of two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Maximize(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = (float)fmax(pv1.x, pv2.x); + pout.y = (float)fmax(pv1.y, pv2.y); +} +//+------------------------------------------------------------------+ +//| Returns a 2D vector that is made up of the smallest components | +//| of two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Minimize(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = (float)fmin(pv1.x, pv2.x); + pout.y = (float)fmin(pv1.y, pv2.y); +} +//+------------------------------------------------------------------+ +//| Returns the normalized version of a 2D vector. | +//+------------------------------------------------------------------+ +void DXVec2Normalize(DXVector2 &pout, const DXVector2 &pv) { + //--- calculate length + float norm = DXVec2Length(pv); + if (!norm) { + pout.x = 0.0f; + pout.y = 0.0f; + } else { + pout.x = pv.x / norm; + pout.y = pv.y / norm; + } +} +//+------------------------------------------------------------------+ +//| Scales a 2D vector. | +//+------------------------------------------------------------------+ +void DXVec2Scale(DXVector2 &pout, const DXVector2 &pv, float s) { + pout.x = s * pv.x; + pout.y = s * pv.y; +} +//+------------------------------------------------------------------+ +//| DXVec3Subtract | +//+------------------------------------------------------------------+ +void DXVec2Subtract(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = pv1.x - pv2.x; + pout.y = pv1.y - pv2.y; +} +//+------------------------------------------------------------------+ +//| Transforms a 2D vector by a given matrix. | +//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//+------------------------------------------------------------------+ +void DXVec2Transform(DXVector4 &pout, const DXVector2 &pv, const DXMatrix &pm) { + DXVector4 out; + out.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[3][0]; + out.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[3][1]; + out.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[3][2]; + out.w = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[3][3]; + pout = out; +} +//+------------------------------------------------------------------+ +//| Transforms a 2D vector by a given matrix, | +//| projecting the result back into w = 1. | +//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//+------------------------------------------------------------------+ +void DXVec2TransformCoord(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { + float norm = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[3][3]; + if (norm) { + pout.x = (pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[3][0]) / norm; + pout.y = (pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[3][1]) / norm; + } else { + pout.x = 0.0f; + pout.y = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Transforms the 2D vector normal by the given matrix. | +//+------------------------------------------------------------------+ +void DXVec2TransformNormal(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { + pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y; + pout.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y; +} +//+------------------------------------------------------------------+ +//| Adds two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Add(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = pv1.x + pv2.x; + pout.y = pv1.y + pv2.y; + pout.z = pv1.z + pv2.z; +} +//+------------------------------------------------------------------+ +//| Returns a point in Barycentric coordinates, | +//| using the specified 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3BaryCentric(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2, const DXVector3 &pv3, float f, + float g) { + pout.x = (1.0f - f - g) * pv1.x + f * pv2.x + g * pv3.x; + pout.y = (1.0f - f - g) * pv1.y + f * pv2.y + g * pv3.y; + pout.z = (1.0f - f - g) * pv1.z + f * pv2.z + g * pv3.z; +} +//+------------------------------------------------------------------+ +//| Performs a Catmull-Rom interpolation, | +//| using the specified 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3CatmullRom(DXVector3 &pout, const DXVector3 &pv0, const DXVector3 &pv1, const DXVector3 &pv2, + const DXVector3 &pv3, float s) { + pout.x = 0.5f * (2.0f * pv1.x + (pv2.x - pv0.x) * s + (2.0f * pv0.x - 5.0f * pv1.x + 4.0f * pv2.x - pv3.x) * s * s + + (pv3.x - 3.0f * pv2.x + 3.0f * pv1.x - pv0.x) * s * s * s); + pout.y = 0.5f * (2.0f * pv1.y + (pv2.y - pv0.y) * s + (2.0f * pv0.y - 5.0f * pv1.y + 4.0f * pv2.y - pv3.y) * s * s + + (pv3.y - 3.0f * pv2.y + 3.0f * pv1.y - pv0.y) * s * s * s); + pout.z = 0.5f * (2.0f * pv1.z + (pv2.z - pv0.z) * s + (2.0f * pv0.z - 5.0f * pv1.z + 4.0f * pv2.z - pv3.z) * s * s + + (pv3.z - 3.0f * pv2.z + 3.0f * pv1.z - pv0.z) * s * s * s); +} +//+------------------------------------------------------------------+ +//| Determines the cross-product of two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Cross(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = pv1.y * pv2.z - pv1.z * pv2.y; + pout.y = pv1.z * pv2.x - pv1.x * pv2.z; + pout.z = pv1.x * pv2.y - pv1.y * pv2.x; +} +//+------------------------------------------------------------------+ +//| Determines the dot product of two 3D vectors. | +//+------------------------------------------------------------------+ +float DXVec3Dot(const DXVector3 &pv1, const DXVector3 &pv2) { return (pv1.x * pv2.x + pv1.y * pv2.y + pv1.z * pv2.z); } +//+------------------------------------------------------------------+ +//| Performs a Hermite spline interpolation, | +//| using the specified 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Hermite(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pt1, const DXVector3 &pv2, + const DXVector3 &pt2, float s) { + float h1 = 2.0f * s * s * s - 3.0f * s * s + 1.0f; + float h2 = s * s * s - 2.0f * s * s + s; + float h3 = -2.0f * s * s * s + 3.0f * s * s; + float h4 = s * s * s - s * s; + //--- calculate interpolated coordinates + pout.x = h1 * pv1.x + h2 * pt1.x + h3 * pv2.x + h4 * pt2.x; + pout.y = h1 * pv1.y + h2 * pt1.y + h3 * pv2.y + h4 * pt2.y; + pout.z = h1 * pv1.z + h2 * pt1.z + h3 * pv2.z + h4 * pt2.z; +} +//+------------------------------------------------------------------+ +//| Returns the length of a 3D vector. | +//+------------------------------------------------------------------+ +float DXVec3Length(const DXVector3 &pv) { return ((float)sqrt(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z)); } +//+------------------------------------------------------------------+ +//| Returns the square of the length of a 3D vector. | +//+------------------------------------------------------------------+ +float DXVec3LengthSq(const DXVector3 &pv) { return ((float)(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z)); } +//+------------------------------------------------------------------+ +//| Performs a linear interpolation between two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Lerp(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2, float s) { + pout.x = (1.0f - s) * pv1.x + s * pv2.x; + pout.y = (1.0f - s) * pv1.y + s * pv2.y; + pout.z = (1.0f - s) * pv1.z + s * pv2.z; +} +//+------------------------------------------------------------------+ +//| Returns a 3D vector that is made up of the largest components | +//| of two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Maximize(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = (float)fmax(pv1.x, pv2.x); + pout.y = (float)fmax(pv1.y, pv2.y); + pout.z = (float)fmax(pv1.z, pv2.z); +} +//+------------------------------------------------------------------+ +//| Returns a 3D vector that is made up of the smallest components | +//| of two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Minimize(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = (float)fmin(pv1.x, pv2.x); + pout.y = (float)fmin(pv1.y, pv2.y); + pout.z = (float)fmin(pv1.z, pv2.z); +} +//+------------------------------------------------------------------+ +//| Returns the normalized version of a 3D vector. | +//+------------------------------------------------------------------+ +void DXVec3Normalize(DXVector3 &pout, const DXVector3 &pv) { + //--- calculate length + float norm = DXVec3Length(pv); + if (!norm) { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + } else { + pout.x = pv.x / norm; + pout.y = pv.y / norm; + pout.z = pv.z / norm; + } +} +//+------------------------------------------------------------------+ +//| Projects a 3D vector from object space into screen space. | +//+------------------------------------------------------------------+ +void DXVec3Project(DXVector3 &pout, const DXVector3 &pv, const DViewport &pviewport, const DXMatrix &pprojection, + const DXMatrix &pview, const DXMatrix &pworld) { + DXMatrix m; + DXMatrixIdentity(m); + //--- pworld + DXMatrixMultiply(m, m, pworld); + //--- pview + DXMatrixMultiply(m, m, pview); + //--- pprojection + DXMatrixMultiply(m, m, pprojection); + DXVec3TransformCoord(pout, pv, m); + //---pviewport + pout.x = pviewport.x + (1.0f + pout.x) * pviewport.width / 2.0f; + pout.y = pviewport.y + (1.0f - pout.y) * pviewport.height / 2.0f; + pout.z = pviewport.minz + pout.z * (pviewport.maxz - pviewport.minz); +} +//+------------------------------------------------------------------+ +//| Scales a 3D vector. | +//+------------------------------------------------------------------+ +void DXVec3Scale(DXVector3 &pout, const DXVector3 &pv, float s) { + pout.x = s * pv.x; + pout.y = s * pv.y; + pout.z = s * pv.z; +} +//+------------------------------------------------------------------+ +//| Subtracts two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Subtract(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = pv1.x - pv2.x; + pout.y = pv1.y - pv2.y; + pout.z = pv1.z - pv2.z; +} +//+------------------------------------------------------------------+ +//| Transforms vector (x,y,z,1) by a given matrix. | +//+------------------------------------------------------------------+ +void DXVec3Transform(DXVector4 &pout, const DXVector3 &pv, const DXMatrix &pm) { + DXVector4 out; + //--- + out.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z + pm.m[3][0]; + out.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z + pm.m[3][1]; + out.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z + pm.m[3][2]; + out.w = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[2][3] * pv.z + pm.m[3][3]; + pout = out; +} +//+------------------------------------------------------------------+ +//| Transforms a 3D vector by a given matrix, | +//| projecting the result back into w = 1. | +//+------------------------------------------------------------------+ +void DXVec3TransformCoord(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { + float norm = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[2][3] * pv.z + pm.m[3][3]; + //--- + if (norm) { + pout.x = (pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z + pm.m[3][0]) / norm; + pout.y = (pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z + pm.m[3][1]) / norm; + pout.z = (pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z + pm.m[3][2]) / norm; + } else { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Transforms the 3D vector normal by the given matrix. | +//+------------------------------------------------------------------+ +void DXVec3TransformNormal(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { + pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z; + pout.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z; + pout.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z; +} +//+------------------------------------------------------------------+ +//| Projects a vector from screen space into object space. | +//+------------------------------------------------------------------+ +void DXVec3Unproject(DXVector3 &out, const DXVector3 &v, const DViewport &viewport, const DXMatrix &projection, + const DXMatrix &view, const DXMatrix &world) { + DXMatrix m; + DXMatrixIdentity(m); + //--- world + DXMatrixMultiply(m, m, world); + //--- view + DXMatrixMultiply(m, m, view); + //--- projection + DXMatrixMultiply(m, m, projection); + //--- calculate inverse matrix + float det = 0.0f; + DXMatrixInverse(m, det, m); + out = v; + //--- viewport + out.x = 2.0f * (out.x - viewport.x) / viewport.width - 1.0f; + out.y = 1.0f - 2.0f * (out.y - viewport.y) / viewport.height; + out.z = (out.z - viewport.minz) / (viewport.maxz - viewport.minz); + //--- + DXVec3TransformCoord(out, out, m); +} +//+------------------------------------------------------------------+ +//| Adds two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Add(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = pv1.x + pv2.x; + pout.y = pv1.y + pv2.y; + pout.z = pv1.z + pv2.z; + pout.w = pv1.w + pv2.w; +} +//+------------------------------------------------------------------+ +//| Returns a point in Barycentric coordinates, | +//| using the specified 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4BaryCentric(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2, const DXVector4 &pv3, float f, + float g) { + pout.x = (1.0f - f - g) * (pv1.x) + f * (pv2.x) + g * (pv3.x); + pout.y = (1.0f - f - g) * (pv1.y) + f * (pv2.y) + g * (pv3.y); + pout.z = (1.0f - f - g) * (pv1.z) + f * (pv2.z) + g * (pv3.z); + pout.w = (1.0f - f - g) * (pv1.w) + f * (pv2.w) + g * (pv3.w); +} +//+------------------------------------------------------------------+ +//| Performs a Catmull-Rom interpolation, | +//| using the specified 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4CatmullRom(DXVector4 &pout, const DXVector4 &pv0, const DXVector4 &pv1, const DXVector4 &pv2, + const DXVector4 &pv3, float s) { + pout.x = 0.5f * (2.0f * pv1.x + (pv2.x - pv0.x) * s + (2.0f * pv0.x - 5.0f * pv1.x + 4.0f * pv2.x - pv3.x) * s * s + + (pv3.x - 3.0f * pv2.x + 3.0f * pv1.x - pv0.x) * s * s * s); + pout.y = 0.5f * (2.0f * pv1.y + (pv2.y - pv0.y) * s + (2.0f * pv0.y - 5.0f * pv1.y + 4.0f * pv2.y - pv3.y) * s * s + + (pv3.y - 3.0f * pv2.y + 3.0f * pv1.y - pv0.y) * s * s * s); + pout.z = 0.5f * (2.0f * pv1.z + (pv2.z - pv0.z) * s + (2.0f * pv0.z - 5.0f * pv1.z + 4.0f * pv2.z - pv3.z) * s * s + + (pv3.z - 3.0f * pv2.z + 3.0f * pv1.z - pv0.z) * s * s * s); + pout.w = 0.5f * (2.0f * pv1.w + (pv2.w - pv0.w) * s + (2.0f * pv0.w - 5.0f * pv1.w + 4.0f * pv2.w - pv3.w) * s * s + + (pv3.w - 3.0f * pv2.w + 3.0f * pv1.w - pv0.w) * s * s * s); +} +//+------------------------------------------------------------------+ +//| Determines the cross-product in four dimensions. | +//+------------------------------------------------------------------+ +void DXVec4Cross(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2, const DXVector4 &pv3) { + DXVector4 out; + out.x = pv1.y * (pv2.z * pv3.w - pv3.z * pv2.w) - pv1.z * (pv2.y * pv3.w - pv3.y * pv2.w) + + pv1.w * (pv2.y * pv3.z - pv2.z * pv3.y); + out.y = -(pv1.x * (pv2.z * pv3.w - pv3.z * pv2.w) - pv1.z * (pv2.x * pv3.w - pv3.x * pv2.w) + + pv1.w * (pv2.x * pv3.z - pv3.x * pv2.z)); + out.z = pv1.x * (pv2.y * pv3.w - pv3.y * pv2.w) - pv1.y * (pv2.x * pv3.w - pv3.x * pv2.w) + + pv1.w * (pv2.x * pv3.y - pv3.x * pv2.y); + out.w = -(pv1.x * (pv2.y * pv3.z - pv3.y * pv2.z) - pv1.y * (pv2.x * pv3.z - pv3.x * pv2.z) + + pv1.z * (pv2.x * pv3.y - pv3.x * pv2.y)); + pout = out; +} +//+------------------------------------------------------------------+ +//| Determines the dot product of two 4D vectors. | +//+------------------------------------------------------------------+ +float DXVec4Dot(const DXVector4 &pv1, const DXVector4 &pv2) { + return (pv1.x * pv2.x + pv1.y * pv2.y + pv1.z * pv2.z + pv1.w * pv2.w); +} +//+------------------------------------------------------------------+ +//| Performs a Hermite spline interpolation, | +//| using the specified 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Hermite(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pt1, const DXVector4 &pv2, + const DXVector4 &pt2, float s) { + float h1 = 2.0f * s * s * s - 3.0f * s * s + 1.0f; + float h2 = s * s * s - 2.0f * s * s + s; + float h3 = -2.0f * s * s * s + 3.0f * s * s; + float h4 = s * s * s - s * s; + pout.x = h1 * pv1.x + h2 * pt1.x + h3 * pv2.x + h4 * pt2.x; + pout.y = h1 * pv1.y + h2 * pt1.y + h3 * pv2.y + h4 * pt2.y; + pout.z = h1 * pv1.z + h2 * pt1.z + h3 * pv2.z + h4 * pt2.z; + pout.w = h1 * pv1.w + h2 * pt1.w + h3 * pv2.w + h4 * pt2.w; +} +//+------------------------------------------------------------------+ +//| Returns the length of a 4D vector. | +//+------------------------------------------------------------------+ +float DXVec4Length(const DXVector4 &pv) { return ((float)sqrt(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z + pv.w * pv.w)); } +//+------------------------------------------------------------------+ +//| Returns the square of the length of a 4D vector. | +//+------------------------------------------------------------------+ +float DXVec4LengthSq(const DXVector4 &pv) { return ((float)(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z)); } +//+------------------------------------------------------------------+ +//| Performs a linear interpolation between two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Lerp(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2, float s) { + pout.x = (1.0f - s) * pv1.x + s * pv2.x; + pout.y = (1.0f - s) * pv1.y + s * pv2.y; + pout.z = (1.0f - s) * pv1.z + s * pv2.z; + pout.w = (1.0f - s) * pv1.w + s * pv2.w; +} +//+------------------------------------------------------------------+ +//| Returns a 4D vector that is made up of the largest components | +//| of two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Maximize(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = (float)fmax(pv1.x, pv2.x); + pout.y = (float)fmax(pv1.y, pv2.y); + pout.z = (float)fmax(pv1.z, pv2.z); + pout.w = (float)fmax(pv1.w, pv2.w); +} +//+------------------------------------------------------------------+ +//| Returns a 4D vector that is made up of the smallest components | +//| of two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Minimize(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = (float)fmin(pv1.x, pv2.x); + pout.y = (float)fmin(pv1.y, pv2.y); + pout.z = (float)fmin(pv1.z, pv2.z); + pout.w = (float)fmin(pv1.w, pv2.w); +} +//+------------------------------------------------------------------+ +//| Returns the normalized version of a 4D vector. | +//+------------------------------------------------------------------+ +void DXVec4Normalize(DXVector4 &pout, const DXVector4 &pv) { + //--- calculate length + float norm = DXVec4Length(pv); + if (!norm) { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + pout.w = 0.0f; + } else { + pout.x = pv.x / norm; + pout.y = pv.y / norm; + pout.z = pv.z / norm; + pout.w = pv.w / norm; + } +} +//+------------------------------------------------------------------+ +//| Scales a 4D vector. | +//+------------------------------------------------------------------+ +void DXVec4Scale(DXVector4 &pout, const DXVector4 &pv, float s) { + pout.x = s * pv.x; + pout.y = s * pv.y; + pout.z = s * pv.z; + pout.w = s * pv.w; +} +//+------------------------------------------------------------------+ +//| Subtracts two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Subtract(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = pv1.x - pv2.x; + pout.y = pv1.y - pv2.y; + pout.z = pv1.z - pv2.z; + pout.w = pv1.w - pv2.w; +} +//+------------------------------------------------------------------+ +//| Transforms a 4D vector by a given matrix. | +//+------------------------------------------------------------------+ +void DXVec4Transform(DXVector4 &pout, const DXVector4 &pv, const DXMatrix &pm) { + DXVector4 temp; + temp.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z + pm.m[3][0] * pv.w; + temp.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z + pm.m[3][1] * pv.w; + temp.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z + pm.m[3][2] * pv.w; + temp.w = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[2][3] * pv.z + pm.m[3][3] * pv.w; + pout = temp; +} +//+------------------------------------------------------------------+ +//| Returns a quaternion in barycentric coordinates. | +//+------------------------------------------------------------------+ +void DXQuaternionBaryCentric(DXQuaternion &pout, DXQuaternion &pq1, DXQuaternion &pq2, DXQuaternion &pq3, float f, + float g) { + DXQuaternion temp1, temp2; + DXQuaternionSlerp(temp1, pq1, pq2, f + g); + DXQuaternionSlerp(temp2, pq1, pq3, f + g); + DXQuaternionSlerp(pout, temp1, temp2, g / (f + g)); +} +//+------------------------------------------------------------------+ +//| Returns the conjugate of a quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionConjugate(DXQuaternion &pout, const DXQuaternion &pq) { + pout.x = -pq.x; + pout.y = -pq.y; + pout.z = -pq.z; + pout.w = pq.w; +} +//+------------------------------------------------------------------+ +//| Returns the dot product of two quaternions. | +//+------------------------------------------------------------------+ +float DXQuaternionDot(DXQuaternion &a, DXQuaternion &b) { return (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w); } +//+------------------------------------------------------------------+ +//| Calculates the exponential. | +//| This method converts a pure quaternion to a unit quaternion. | +//| DXQuaternionExp expects a pure quaternion, where w is ignored | +//| in the calculation (w == 0). | +//+------------------------------------------------------------------+ +void DXQuaternionExp(DXQuaternion &out, const DXQuaternion &q) { + float norm = (float)sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + if (norm) { + out.x = (float)sin(norm) * q.x / norm; + out.y = (float)sin(norm) * q.y / norm; + out.z = (float)sin(norm) * q.z / norm; + out.w = (float)cos(norm); + } else { + out.x = 0.0f; + out.y = 0.0f; + out.z = 0.0f; + out.w = 1.0f; + } +} +//+------------------------------------------------------------------+ +//| Returns the identity quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionIdentity(DXQuaternion &out) { + out.x = 0.0f; + out.y = 0.0f; + out.z = 0.0f; + out.w = 1.0f; +} +//+------------------------------------------------------------------+ +//| Determines if a quaternion is an identity quaternion. | +//+------------------------------------------------------------------+ +bool DXQuaternionIsIdentity(DXQuaternion &pq) { + return ((pq.x == 0.0f) && (pq.y == 0.0f) && (pq.z == 0.0f) && (pq.w == 1.0f)); +} +//+------------------------------------------------------------------+ +//| Returns the length of a quaternion. | +//+------------------------------------------------------------------+ +float DXQuaternionLength(const DXQuaternion &pq) { + return ((float)sqrt(pq.x * pq.x + pq.y * pq.y + pq.z * pq.z + pq.w * pq.w)); +} +//+------------------------------------------------------------------+ +//| Returns the square of the length of a quaternion. | +//+------------------------------------------------------------------+ +float DXQuaternionLengthSq(const DXQuaternion &pq) { + return ((float)(pq.x * pq.x + pq.y * pq.y + pq.z * pq.z + pq.w * pq.w)); +} +//+------------------------------------------------------------------+ +//| Conjugates and renormalizes a quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionInverse(DXQuaternion &pout, const DXQuaternion &pq) { + float norm = DXQuaternionLengthSq(pq); + pout.x = -pq.x / norm; + pout.y = -pq.y / norm; + pout.z = -pq.z / norm; + pout.w = pq.w / norm; +} +//+------------------------------------------------------------------+ +//| Calculates the natural logarithm. | +//| The DXQuaternionLn function works only for unit quaternions. | +//+------------------------------------------------------------------+ +void DXQuaternionLn(DXQuaternion &out, const DXQuaternion &q) { + float t; + if ((q.w >= 1.0f) || (q.w == -1.0f)) + t = 1.0f; + else + t = (float)(acos(q.w) / sqrt(1.0f - q.w * q.w)); + out.x = t * q.x; + out.y = t * q.y; + out.z = t * q.z; + out.w = 0.0f; +} +//+------------------------------------------------------------------+ +//| Multiplies two quaternions. | +//+------------------------------------------------------------------+ +void DXQuaternionMultiply(DXQuaternion &pout, const DXQuaternion &pq1, const DXQuaternion &pq2) { + DXQuaternion out; + out.x = pq2.w * pq1.x + pq2.x * pq1.w + pq2.y * pq1.z - pq2.z * pq1.y; + out.y = pq2.w * pq1.y - pq2.x * pq1.z + pq2.y * pq1.w + pq2.z * pq1.x; + out.z = pq2.w * pq1.z + pq2.x * pq1.y - pq2.y * pq1.x + pq2.z * pq1.w; + out.w = pq2.w * pq1.w - pq2.x * pq1.x - pq2.y * pq1.y - pq2.z * pq1.z; + pout = out; +} +//+------------------------------------------------------------------+ +//| Computes a unit length quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionNormalize(DXQuaternion &out, const DXQuaternion &q) { + float norm = DXQuaternionLength(q); + if (!norm) { + out.x = 0.0f; + out.y = 0.0f; + out.z = 0.0f; + out.w = 0.0f; + } else { + out.x = q.x / norm; + out.y = q.y / norm; + out.z = q.z / norm; + out.w = q.w / norm; + } +} +//+------------------------------------------------------------------+ +//| Rotates a quaternion about an arbitrary axis. | +//+------------------------------------------------------------------+ +void DXQuaternionRotationAxis(DXQuaternion &out, const DXVector3 &v, float angle) { + DXVector3 temp; + DXVec3Normalize(temp, v); + out.x = (float)sin(angle / 2.0f) * temp.x; + out.y = (float)sin(angle / 2.0f) * temp.y; + out.z = (float)sin(angle / 2.0f) * temp.z; + out.w = (float)cos(angle / 2.0f); +} +//+------------------------------------------------------------------+ +//| Builds a quaternion from a rotation matrix. | +//+------------------------------------------------------------------+ +void DXQuaternionRotationMatrix(DXQuaternion &out, const DXMatrix &m) { + float s; + float trace = m.m[0][0] + m.m[1][1] + m.m[2][2] + 1.0f; + if (trace > 1.0f) { + s = 2.0f * (float)sqrt(trace); + out.x = (m.m[1][2] - m.m[2][1]) / s; + out.y = (m.m[2][0] - m.m[0][2]) / s; + out.z = (m.m[0][1] - m.m[1][0]) / s; + out.w = 0.25f * s; + } else { + int maxi = 0; + for (int i = 1; i < 3; i++) { + if (m.m[i][i] > m.m[maxi][maxi]) maxi = i; + } + switch (maxi) { + case 0: + s = 2.0f * (float)sqrt(1.0f + m.m[0][0] - m.m[1][1] - m.m[2][2]); + out.x = 0.25f * s; + out.y = (m.m[0][1] + m.m[1][0]) / s; + out.z = (m.m[0][2] + m.m[2][0]) / s; + out.w = (m.m[1][2] - m.m[2][1]) / s; + break; + + case 1: + s = 2.0f * (float)sqrt(1.0f + m.m[1][1] - m.m[0][0] - m.m[2][2]); + out.x = (m.m[0][1] + m.m[1][0]) / s; + out.y = 0.25f * s; + out.z = (m.m[1][2] + m.m[2][1]) / s; + out.w = (m.m[2][0] - m.m[0][2]) / s; + break; + + case 2: + s = 2.0f * (float)sqrt(1.0f + m.m[2][2] - m.m[0][0] - m.m[1][1]); + out.x = (m.m[0][2] + m.m[2][0]) / s; + out.y = (m.m[1][2] + m.m[2][1]) / s; + out.z = 0.25f * s; + out.w = (m.m[0][1] - m.m[1][0]) / s; + break; + } + } +} +//+------------------------------------------------------------------+ +//| Builds a quaternion with the given yaw, pitch, and roll. | +//+------------------------------------------------------------------+ +void DXQuaternionRotationYawPitchRoll(DXQuaternion &out, float yaw, float pitch, float roll) { + float syaw = (float)sin(yaw / 2.0f); + float cyaw = (float)cos(yaw / 2.0f); + float spitch = (float)sin(pitch / 2.0f); + float cpitch = (float)cos(pitch / 2.0f); + float sroll = (float)sin(roll / 2.0f); + float croll = (float)cos(roll / 2.0f); + //--- + out.x = syaw * cpitch * sroll + cyaw * spitch * croll; + out.y = syaw * cpitch * croll - cyaw * spitch * sroll; + out.z = cyaw * cpitch * sroll - syaw * spitch * croll; + out.w = cyaw * cpitch * croll + syaw * spitch * sroll; +} +//+------------------------------------------------------------------+ +//| Interpolates between two quaternions, using spherical linear | +//| interpolation. | +//+------------------------------------------------------------------+ +void DXQuaternionSlerp(DXQuaternion &out, DXQuaternion &q1, DXQuaternion &q2, float t) { + float temp = 1.0f - t; + float dot = DXQuaternionDot(q1, q2); + if (dot < 0.0f) { + t = -t; + dot = -dot; + } + if (1.0f - dot > 0.001f) { + float theta = (float)acos(dot); + temp = (float)sin(theta * temp) / (float)sin(theta); + t = (float)sin(theta * t) / (float)sin(theta); + } + out.x = temp * q1.x + t * q2.x; + out.y = temp * q1.y + t * q2.y; + out.z = temp * q1.z + t * q2.z; + out.w = temp * q1.w + t * q2.w; +} +//+------------------------------------------------------------------+ +//| Interpolates between quaternions, using spherical quadrangle | +//| interpolation. | +//+------------------------------------------------------------------+ +void DXQuaternionSquad(DXQuaternion &pout, DXQuaternion &pq1, DXQuaternion &pq2, DXQuaternion &pq3, DXQuaternion &pq4, + float t) { + DXQuaternion temp1, temp2; + DXQuaternionSlerp(temp1, pq1, pq4, t); + DXQuaternionSlerp(temp2, pq2, pq3, t); + DXQuaternionSlerp(pout, temp1, temp2, 2.0f * t * (1.0f - t)); +} +//+------------------------------------------------------------------+ +//| add_diff | +//+------------------------------------------------------------------+ +DXQuaternion add_diff(const DXQuaternion &q1, const DXQuaternion &q2, const float add) { + DXQuaternion temp; + temp.x = q1.x + add * q2.x; + temp.y = q1.y + add * q2.y; + temp.z = q1.z + add * q2.z; + temp.w = q1.w + add * q2.w; + //--- + return (temp); +} +//+------------------------------------------------------------------+ +//| Sets up control points for spherical quadrangle interpolation. | +//+------------------------------------------------------------------+ +void DXQuaternionSquadSetup(DXQuaternion &paout, DXQuaternion &pbout, DXQuaternion &pcout, DXQuaternion &pq0, + DXQuaternion &pq1, DXQuaternion &pq2, DXQuaternion &pq3) { + DXQuaternion q, temp1, temp2, temp3, zero; + DXQuaternion aout, cout; + zero.x = 0.0f; + zero.y = 0.0f; + zero.z = 0.0f; + zero.w = 0.0f; + //--- + if (DXQuaternionDot(pq0, pq1) < 0.0f) + temp2 = add_diff(zero, pq0, -1.0f); + else + temp2 = pq0; + //--- + if (DXQuaternionDot(pq1, pq2) < 0.0f) + cout = add_diff(zero, pq2, -1.0f); + else + cout = pq2; + //--- + if (DXQuaternionDot(cout, pq3) < 0.0f) + temp3 = add_diff(zero, pq3, -1.0f); + else + temp3 = pq3; + //--- + DXQuaternionInverse(temp1, pq1); + DXQuaternionMultiply(temp2, temp1, temp2); + DXQuaternionLn(temp2, temp2); + DXQuaternionMultiply(q, temp1, cout); + DXQuaternionLn(q, q); + temp1 = add_diff(temp2, q, 1.0f); + temp1.x *= -0.25f; + temp1.y *= -0.25f; + temp1.z *= -0.25f; + temp1.w *= -0.25f; + DXQuaternionExp(temp1, temp1); + DXQuaternionMultiply(aout, pq1, temp1); + //--- + DXQuaternionInverse(temp1, cout); + DXQuaternionMultiply(temp2, temp1, pq1); + DXQuaternionLn(temp2, temp2); + DXQuaternionMultiply(q, temp1, temp3); + DXQuaternionLn(q, q); + temp1 = add_diff(temp2, q, 1.0f); + temp1.x *= -0.25f; + temp1.y *= -0.25f; + temp1.z *= -0.25f; + temp1.w *= -0.25f; + DXQuaternionExp(temp1, temp1); + DXQuaternionMultiply(pbout, cout, temp1); + paout = aout; + pcout = cout; +} +//+------------------------------------------------------------------+ +//| Computes a quaternion's axis and angle of rotation. | +//+------------------------------------------------------------------+ +void DXQuaternionToAxisAngle(const DXQuaternion &pq, DXVector3 &paxis, float &pangle) { + //--- paxis + paxis.x = pq.x; + paxis.y = pq.y; + paxis.z = pq.z; + //--- pangle + pangle = 2.0f * (float)acos(pq.w); +} +//+------------------------------------------------------------------+ +//| DXMatrixIdentity creates an identity matrix | +//+------------------------------------------------------------------+ +void DXMatrixIdentity(DXMatrix &out) { + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) { + if (i == j) + out.m[j, i] = 1.0f; + else + out.m[j, i] = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Determines if a matrix is an identity matrix. | +//+------------------------------------------------------------------+ +bool DXMatrixIsIdentity(DXMatrix &pm) { + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) { + if (i == j) { + if (fabs(pm.m[j, i] - 1.0f) > 1e-6f) return (false); + } else if (fabs(pm.m[j, i]) > 1e-6f) + return (false); + } + //--- + return (true); +} +//+------------------------------------------------------------------+ +//| Builds a 3D affine transformation matrix. | +//+------------------------------------------------------------------+ +//| This function calculates the affine transformation matrix | +//| with the following formula, with matrix concatenation | +//| evaluated in left-to-right order: | +//| Mout = Ms * (Mrc)-1 * Mr * Mrc * Mt | +//| where: | +//| Mout = output matrix (pOut) | +//| Ms = scaling matrix (Scaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (pRotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixAffineTransformation(DXMatrix &out, float scaling, const DXVector3 &rotationcenter, + const DXQuaternion &rotation, const DXVector3 &translation) { + DXMatrixIdentity(out); + //--- rotation + float temp00 = 1.0f - 2.0f * (rotation.y * rotation.y + rotation.z * rotation.z); + float temp01 = 2.0f * (rotation.x * rotation.y + rotation.z * rotation.w); + float temp02 = 2.0f * (rotation.x * rotation.z - rotation.y * rotation.w); + float temp10 = 2.0f * (rotation.x * rotation.y - rotation.z * rotation.w); + float temp11 = 1.0f - 2.0f * (rotation.x * rotation.x + rotation.z * rotation.z); + float temp12 = 2.0f * (rotation.y * rotation.z + rotation.x * rotation.w); + float temp20 = 2.0f * (rotation.x * rotation.z + rotation.y * rotation.w); + float temp21 = 2.0f * (rotation.y * rotation.z - rotation.x * rotation.w); + float temp22 = 1.0f - 2.0f * (rotation.x * rotation.x + rotation.y * rotation.y); + //--- scaling + out.m[0][0] = scaling * temp00; + out.m[0][1] = scaling * temp01; + out.m[0][2] = scaling * temp02; + out.m[1][0] = scaling * temp10; + out.m[1][1] = scaling * temp11; + out.m[1][2] = scaling * temp12; + out.m[2][0] = scaling * temp20; + out.m[2][1] = scaling * temp21; + out.m[2][2] = scaling * temp22; + //--- rotationcenter + out.m[3][0] = rotationcenter.x * (1.0f - temp00) - rotationcenter.y * temp10 - rotationcenter.z * temp20; + out.m[3][1] = rotationcenter.y * (1.0f - temp11) - rotationcenter.x * temp01 - rotationcenter.z * temp21; + out.m[3][2] = rotationcenter.z * (1.0f - temp22) - rotationcenter.x * temp02 - rotationcenter.y * temp12; + //--- translation + out.m[3][0] += translation.x; + out.m[3][1] += translation.y; + out.m[3][2] += translation.z; +} +//+------------------------------------------------------------------+ +//| Builds a 2D affine transformation matrix in the xy plane. | +//+------------------------------------------------------------------+ +//| This function calculates the affine transformation matrix | +//| with the following formula, with matrix concatenation evaluated | +//| in left-to-right order: | +//| Mout = Ms * (Mrc)^(-1) * Mr * Mrc * Mt | +//| where: | +//| Mout = output matrix (pOut) | +//| Ms = scaling matrix (Scaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (Rotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector2 &rotationcenter, float rotation, + const DXVector2 &translation) { + float s = (float)sin(rotation / 2.0f); + float tmp1 = 1.0f - 2.0f * s * s; + float tmp2 = 2.0f * s * (float)cos(rotation / 2.0f); + //--- + DXMatrixIdentity(out); + out.m[0][0] = scaling * tmp1; + out.m[0][1] = scaling * tmp2; + out.m[1][0] = -scaling * tmp2; + out.m[1][1] = scaling * tmp1; + //--- rotationcenter + float x = rotationcenter.x; + float y = rotationcenter.y; + out.m[3][0] = y * tmp2 - x * tmp1 + x; + out.m[3][1] = -x * tmp2 - y * tmp1 + y; + //--- translation + out.m[3][0] += translation.x; + out.m[3][1] += translation.y; +} +#define D3DERR_INVALIDCALL -2005530516 +//#define S_OK 0; +//+------------------------------------------------------------------+ +//| Breaks down a general 3D transformation matrix into its scalar, | +//| rotational, and translational components. | +//+------------------------------------------------------------------+ +int DXMatrixDecompose(DXVector3 &poutscale, DXQuaternion &poutrotation, DXVector3 &pouttranslation, + const DXMatrix &pm) { + DXMatrix normalized; + DXVector3 vec; + //--- Compute the scaling part + vec.x = pm.m[0][0]; + vec.y = pm.m[0][1]; + vec.z = pm.m[0][2]; + poutscale.x = DXVec3Length(vec); + vec.x = pm.m[1][0]; + vec.y = pm.m[1][1]; + vec.z = pm.m[1][2]; + poutscale.y = DXVec3Length(vec); + vec.x = pm.m[2][0]; + vec.y = pm.m[2][1]; + vec.z = pm.m[2][2]; + poutscale.z = DXVec3Length(vec); + //--- compute the translation part + pouttranslation.x = pm.m[3][0]; + pouttranslation.y = pm.m[3][1]; + pouttranslation.z = pm.m[3][2]; + //--- let's calculate the rotation now + if ((poutscale.x == 0.0f) || (poutscale.y == 0.0f) || (poutscale.z == 0.0f)) return (D3DERR_INVALIDCALL); + //--- + normalized.m[0][0] = pm.m[0][0] / poutscale.x; + normalized.m[0][1] = pm.m[0][1] / poutscale.x; + normalized.m[0][2] = pm.m[0][2] / poutscale.x; + normalized.m[1][0] = pm.m[1][0] / poutscale.y; + normalized.m[1][1] = pm.m[1][1] / poutscale.y; + normalized.m[1][2] = pm.m[1][2] / poutscale.y; + normalized.m[2][0] = pm.m[2][0] / poutscale.z; + normalized.m[2][1] = pm.m[2][1] / poutscale.z; + normalized.m[2][2] = pm.m[2][2] / poutscale.z; + DXQuaternionRotationMatrix(poutrotation, normalized); + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Returns the determinant of a matrix. | +//+------------------------------------------------------------------+ +float DXMatrixDeterminant(const DXMatrix &pm) { + float t[3], v[4]; + t[0] = pm.m[2][2] * pm.m[3][3] - pm.m[2][3] * pm.m[3][2]; + t[1] = pm.m[1][2] * pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; + t[2] = pm.m[1][2] * pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; + v[0] = pm.m[1][1] * t[0] - pm.m[2][1] * t[1] + pm.m[3][1] * t[2]; + v[1] = -pm.m[1][0] * t[0] + pm.m[2][0] * t[1] - pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[1][0] * pm.m[2][1] - pm.m[2][0] * pm.m[1][1]; + t[1] = pm.m[1][0] * pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; + t[2] = pm.m[2][0] * pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; + v[2] = pm.m[3][3] * t[0] - pm.m[2][3] * t[1] + pm.m[1][3] * t[2]; + v[3] = -pm.m[3][2] * t[0] + pm.m[2][2] * t[1] - pm.m[1][2] * t[2]; + //--- + return (pm.m[0][0] * v[0] + pm.m[0][1] * v[1] + pm.m[0][2] * v[2] + pm.m[0][3] * v[3]); +} +//+------------------------------------------------------------------+ +//| Calculates the inverse of a matrix. | +//+------------------------------------------------------------------+ +void DXMatrixInverse(DXMatrix &pout, float &pdeterminant, const DXMatrix &pm) { + float t[3], v[16]; + t[0] = pm.m[2][2] * pm.m[3][3] - pm.m[2][3] * pm.m[3][2]; + t[1] = pm.m[1][2] * pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; + t[2] = pm.m[1][2] * pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; + v[0] = pm.m[1][1] * t[0] - pm.m[2][1] * t[1] + pm.m[3][1] * t[2]; + v[4] = -pm.m[1][0] * t[0] + pm.m[2][0] * t[1] - pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[1][0] * pm.m[2][1] - pm.m[2][0] * pm.m[1][1]; + t[1] = pm.m[1][0] * pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; + t[2] = pm.m[2][0] * pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; + v[8] = pm.m[3][3] * t[0] - pm.m[2][3] * t[1] + pm.m[1][3] * t[2]; + v[12] = -pm.m[3][2] * t[0] + pm.m[2][2] * t[1] - pm.m[1][2] * t[2]; + //--- + float det = pm.m[0][0] * v[0] + pm.m[0][1] * v[4] + pm.m[0][2] * v[8] + pm.m[0][3] * v[12]; + if (det == 0.0f) { + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) { + pout.m[j, i] = 0.0; + } + //--- + return; + } + if (pdeterminant) pdeterminant = det; + //--- + t[0] = pm.m[2][2] * pm.m[3][3] - pm.m[2][3] * pm.m[3][2]; + t[1] = pm.m[0][2] * pm.m[3][3] - pm.m[0][3] * pm.m[3][2]; + t[2] = pm.m[0][2] * pm.m[2][3] - pm.m[0][3] * pm.m[2][2]; + v[1] = -pm.m[0][1] * t[0] + pm.m[2][1] * t[1] - pm.m[3][1] * t[2]; + v[5] = pm.m[0][0] * t[0] - pm.m[2][0] * t[1] + pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[0][0] * pm.m[2][1] - pm.m[2][0] * pm.m[0][1]; + t[1] = pm.m[3][0] * pm.m[0][1] - pm.m[0][0] * pm.m[3][1]; + t[2] = pm.m[2][0] * pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; + v[9] = -pm.m[3][3] * t[0] - pm.m[2][3] * t[1] - pm.m[0][3] * t[2]; + v[13] = pm.m[3][2] * t[0] + pm.m[2][2] * t[1] + pm.m[0][2] * t[2]; + //--- + t[0] = pm.m[1][2] * pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; + t[1] = pm.m[0][2] * pm.m[3][3] - pm.m[0][3] * pm.m[3][2]; + t[2] = pm.m[0][2] * pm.m[1][3] - pm.m[0][3] * pm.m[1][2]; + v[2] = pm.m[0][1] * t[0] - pm.m[1][1] * t[1] + pm.m[3][1] * t[2]; + v[6] = -pm.m[0][0] * t[0] + pm.m[1][0] * t[1] - pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[0][0] * pm.m[1][1] - pm.m[1][0] * pm.m[0][1]; + t[1] = pm.m[3][0] * pm.m[0][1] - pm.m[0][0] * pm.m[3][1]; + t[2] = pm.m[1][0] * pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; + v[10] = pm.m[3][3] * t[0] + pm.m[1][3] * t[1] + pm.m[0][3] * t[2]; + v[14] = -pm.m[3][2] * t[0] - pm.m[1][2] * t[1] - pm.m[0][2] * t[2]; + //--- + t[0] = pm.m[1][2] * pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; + t[1] = pm.m[0][2] * pm.m[2][3] - pm.m[0][3] * pm.m[2][2]; + t[2] = pm.m[0][2] * pm.m[1][3] - pm.m[0][3] * pm.m[1][2]; + v[3] = -pm.m[0][1] * t[0] + pm.m[1][1] * t[1] - pm.m[2][1] * t[2]; + v[7] = pm.m[0][0] * t[0] - pm.m[1][0] * t[1] + pm.m[2][0] * t[2]; + //--- + v[11] = -pm.m[0][0] * (pm.m[1][1] * pm.m[2][3] - pm.m[1][3] * pm.m[2][1]) + + pm.m[1][0] * (pm.m[0][1] * pm.m[2][3] - pm.m[0][3] * pm.m[2][1]) - + pm.m[2][0] * (pm.m[0][1] * pm.m[1][3] - pm.m[0][3] * pm.m[1][1]); + //--- + v[15] = pm.m[0][0] * (pm.m[1][1] * pm.m[2][2] - pm.m[1][2] * pm.m[2][1]) - + pm.m[1][0] * (pm.m[0][1] * pm.m[2][2] - pm.m[0][2] * pm.m[2][1]) + + pm.m[2][0] * (pm.m[0][1] * pm.m[1][2] - pm.m[0][2] * pm.m[1][1]); + //--- + det = 1.0f / det; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) pout.m[i][j] = v[4 * i + j] * det; +} +//+------------------------------------------------------------------+ +//| Builds a left-handed,look-at matrix. | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| | +//| zaxis = normal(At - Eye) | +//| xaxis = normal(cross(Up,zaxis)) | +//| yaxis = cross(zaxis,xaxis) | +//| | +//| xaxis.x yaxis.x zaxis.x 0 | +//| xaxis.y yaxis.y zaxis.y 0 | +//| xaxis.z yaxis.z zaxis.z 0 | +//| -dot(xaxis,eye) -dot(yaxis,eye) -dot(zaxis,eye) 1 | +//+------------------------------------------------------------------+ +void DXMatrixLookAtLH(DXMatrix &out, const DXVector3 &eye, const DXVector3 &at, const DXVector3 &up) { + DXVector3 right, upn, vec; + DXVec3Subtract(vec, at, eye); + DXVec3Normalize(vec, vec); + DXVec3Cross(right, up, vec); + DXVec3Cross(upn, vec, right); + DXVec3Normalize(right, right); + DXVec3Normalize(upn, upn); + //--- + out.m[0][0] = right.x; + out.m[1][0] = right.y; + out.m[2][0] = right.z; + out.m[3][0] = -DXVec3Dot(right, eye); + out.m[0][1] = upn.x; + out.m[1][1] = upn.y; + out.m[2][1] = upn.z; + out.m[3][1] = -DXVec3Dot(upn, eye); + out.m[0][2] = vec.x; + out.m[1][2] = vec.y; + out.m[2][2] = vec.z; + out.m[3][2] = -DXVec3Dot(vec, eye); + out.m[0][3] = 0.0f; + out.m[1][3] = 0.0f; + out.m[2][3] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Builds a right-handed, look-at matrix. | +//+------------------------------------------------------------------+ +//| This function uses the following formula to compute | +//| the returned matrix. | +//| | +//| zaxis = normal(Eye - At) | +//| xaxis = normal(cross(Up,zaxis)) | +//| yaxis = cross(zaxis,xaxis) | +//| | +//| xaxis.x yaxis.x zaxis.x 0 | +//| xaxis.y yaxis.y zaxis.y 0 | +//| xaxis.z yaxis.z zaxis.z 0 | +//| dot(xaxis,eye) dot(yaxis,eye) dot(zaxis,eye) 1 | +//+------------------------------------------------------------------+ +void DXMatrixLookAtRH(DXMatrix &out, const DXVector3 &eye, const DXVector3 &at, const DXVector3 &up) { + DXVector3 right, upn, vec; + DXVec3Subtract(vec, at, eye); + DXVec3Normalize(vec, vec); + DXVec3Cross(right, up, vec); + DXVec3Cross(upn, vec, right); + DXVec3Normalize(right, right); + DXVec3Normalize(upn, upn); + //--- + out.m[0][0] = -right.x; + out.m[1][0] = -right.y; + out.m[2][0] = -right.z; + out.m[3][0] = DXVec3Dot(right, eye); + out.m[0][1] = upn.x; + out.m[1][1] = upn.y; + out.m[2][1] = upn.z; + out.m[3][1] = -DXVec3Dot(upn, eye); + out.m[0][2] = -vec.x; + out.m[1][2] = -vec.y; + out.m[2][2] = -vec.z; + out.m[3][2] = DXVec3Dot(vec, eye); + out.m[0][3] = 0.0f; + out.m[1][3] = 0.0f; + out.m[2][3] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Determines the product of two matrices. | +//+------------------------------------------------------------------+ +void DXMatrixMultiply(DXMatrix &pout, const DXMatrix &pm1, const DXMatrix &pm2) { + DXMatrix out = {}; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + out.m[i][j] = + pm1.m[i][0] * pm2.m[0][j] + pm1.m[i][1] * pm2.m[1][j] + pm1.m[i][2] * pm2.m[2][j] + pm1.m[i][3] * pm2.m[3][j]; + } + } + pout = out; +} +//+------------------------------------------------------------------+ +//| Calculates the transposed product of two matrices. | +//+------------------------------------------------------------------+ +void DXMatrixMultiplyTranspose(DXMatrix &pout, const DXMatrix &pm1, const DXMatrix &pm2) { + DXMatrix temp = {}; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + temp.m[j][i] = + pm1.m[i][0] * pm2.m[0][j] + pm1.m[i][1] * pm2.m[1][j] + pm1.m[i][2] * pm2.m[2][j] + pm1.m[i][3] * pm2.m[3][j]; + pout = temp; +} +//+------------------------------------------------------------------+ +//| Builds a left-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +void DXMatrixOrthoLH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f / w; + pout.m[1][1] = 2.0f / h; + pout.m[2][2] = 1.0f / (zf - zn); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a customized,left-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +void DXMatrixOrthoOffCenterLH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f / (r - l); + pout.m[1][1] = 2.0f / (t - b); + pout.m[2][2] = 1.0f / (zf - zn); + pout.m[3][0] = -1.0f - 2.0f * l / (r - l); + pout.m[3][1] = 1.0f + 2.0f * t / (b - t); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a customized,right-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +void DXMatrixOrthoOffCenterRH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f / (r - l); + pout.m[1][1] = 2.0f / (t - b); + pout.m[2][2] = 1.0f / (zn - zf); + pout.m[3][0] = -1.0f - 2.0f * l / (r - l); + pout.m[3][1] = 1.0f + 2.0f * t / (b - t); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a right-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixOrthoRH function | +//| are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix: | +//| 2/w 0 0 0 | +//| 0 2/h 0 0 | +//| 0 0 1/(zn-zf) 0 | +//| 0 0 zn/(zn-zf) 1 | +//+------------------------------------------------------------------+ +void DXMatrixOrthoRH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + pout.m[0][0] = 2.0f / w; + pout.m[1][1] = 2.0f / h; + pout.m[2][2] = 1.0f / (zn - zf); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a left-handed perspective projection matrix | +//| based on a field of view. | +//+------------------------------------------------------------------+ +//| This function computes the returned matrix as shown: | +//| xScale 0 0 0 | +//| 0 yScale 0 0 | +//| 0 0 zf/(zf-zn) 1 | +//| 0 0 -zn*zf/(zf-zn) 0 | +//| where: | +//| yScale = cot(fovY/2) | +//| xScale = yScale / aspect ratio | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveFovLH(DXMatrix &pout, float fovy, float aspect, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f / (aspect * (float)tan(fovy / 2.0f)); + pout.m[1][1] = 1.0f / (float)tan(fovy / 2.0f); + pout.m[2][2] = zf / (zf - zn); + pout.m[2][3] = 1.0f; + pout.m[3][2] = (zf * zn) / (zn - zf); + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a right-handed perspective projection matrix | +//| based on a field of view. | +//+------------------------------------------------------------------+ +//| This function computes the returned matrix as shown. | +//| xScale 0 0 0 | +//| 0 yScale 0 0 | +//| 0 0 zf/(zn-zf) -1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//| where: | +//| yScale = cot(fovY/2) | +//| xScale = yScale / aspect ratio | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveFovRH(DXMatrix &pout, float fovy, float aspect, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f / (aspect * (float)tan(fovy / 2.0f)); + pout.m[1][1] = 1.0f / (float)tan(fovy / 2.0f); + pout.m[2][2] = zf / (zn - zf); + pout.m[2][3] = -1.0f; + pout.m[3][2] = (zf * zn) / (zn - zf); + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a left-handed perspective projection matrix | +//+------------------------------------------------------------------+ +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/w 0 0 0 | +//| 0 2*zn/h 0 0 | +//| 0 0 zf/(zf-zn) 1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveLH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + pout.m[0][0] = 2.0f * zn / w; + pout.m[1][1] = 2.0f * zn / h; + pout.m[2][2] = zf / (zf - zn); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = 1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a customized, left-handed perspective projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixPerspectiveOffCenterLH | +//| function are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/(r-l) 0 0 0 | +//| 0 2*zn/(t-b) 0 0 | +//| (l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f * zn / (r - l); + pout.m[1][1] = -2.0f * zn / (b - t); + pout.m[2][0] = -1.0f - 2.0f * l / (r - l); + pout.m[2][1] = 1.0f + 2.0f * t / (b - t); + pout.m[2][2] = -zf / (zn - zf); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = 1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a customized, right-handed perspective projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixPerspectiveOffCenterRH | +//| function are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/(r-l) 0 0 0 | +//| 0 2*zn/(t-b) 0 0 | +//| (l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f * zn / (r - l); + pout.m[1][1] = -2.0f * zn / (b - t); + pout.m[2][0] = 1.0f + 2.0f * l / (r - l); + pout.m[2][1] = -1.0f - 2.0f * t / (b - t); + pout.m[2][2] = zf / (zn - zf); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = -1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a right-handed perspective projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixPerspectiveRH function | +//| are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/w 0 0 0 | +//| 0 2*zn/h 0 0 | +//| 0 0 zf/(zn-zf) -1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveRH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f * zn / w; + pout.m[1][1] = 2.0f * zn / h; + pout.m[2][2] = zf / (zn - zf); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = -1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that reflects the coordinate system about a plane| +//| This function normalizes the plane equation before it creates | +//| the reflected matrix. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| P = normalize(Plane); | +//| -2 * P.a * P.a + 1 -2 * P.b * P.a -2 * P.c * P.a 0 | +//| -2 * P.a * P.b -2 * P.b * P.b + 1 -2 * P.c * P.b 0 | +//| -2 * P.a * P.c -2 * P.b * P.c -2 * P.c * P.c + 1 0 | +//| -2 * P.a * P.d -2 * P.b * P.d -2 * P.c * P.d 1 | +//+------------------------------------------------------------------+ +void DXMatrixReflect(DXMatrix &pout, const DXPlane &pplane) { + DXPlane Nplane; + DXPlaneNormalize(Nplane, pplane); + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f - 2.0f * Nplane.a * Nplane.a; + pout.m[0][1] = -2.0f * Nplane.a * Nplane.b; + pout.m[0][2] = -2.0f * Nplane.a * Nplane.c; + pout.m[1][0] = -2.0f * Nplane.a * Nplane.b; + pout.m[1][1] = 1.0f - 2.0f * Nplane.b * Nplane.b; + pout.m[1][2] = -2.0f * Nplane.b * Nplane.c; + pout.m[2][0] = -2.0f * Nplane.c * Nplane.a; + pout.m[2][1] = -2.0f * Nplane.c * Nplane.b; + pout.m[2][2] = 1.0f - 2.0f * Nplane.c * Nplane.c; + pout.m[3][0] = -2.0f * Nplane.d * Nplane.a; + pout.m[3][1] = -2.0f * Nplane.d * Nplane.b; + pout.m[3][2] = -2.0f * Nplane.d * Nplane.c; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around an arbitrary axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationAxis(DXMatrix &out, const DXVector3 &v, float angle) { + DXVector3 nv; + DXVec3Normalize(nv, v); + //--- + float sangle = (float)sin(angle); + float cangle = (float)cos(angle); + float cdiff = 1.0f - cangle; + //--- + out.m[0][0] = cdiff * nv.x * nv.x + cangle; + out.m[1][0] = cdiff * nv.x * nv.y - sangle * nv.z; + out.m[2][0] = cdiff * nv.x * nv.z + sangle * nv.y; + out.m[3][0] = 0.0f; + out.m[0][1] = cdiff * nv.y * nv.x + sangle * nv.z; + out.m[1][1] = cdiff * nv.y * nv.y + cangle; + out.m[2][1] = cdiff * nv.y * nv.z - sangle * nv.x; + out.m[3][1] = 0.0f; + out.m[0][2] = cdiff * nv.z * nv.x - sangle * nv.y; + out.m[1][2] = cdiff * nv.z * nv.y + sangle * nv.x; + out.m[2][2] = cdiff * nv.z * nv.z + cangle; + out.m[3][2] = 0.0f; + out.m[0][3] = 0.0f; + out.m[1][3] = 0.0f; + out.m[2][3] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Builds a rotation matrix from a quaternion. | +//+------------------------------------------------------------------+ +void DXMatrixRotationQuaternion(DXMatrix &pout, const DXQuaternion &pq) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f - 2.0f * (pq.y * pq.y + pq.z * pq.z); + pout.m[0][1] = 2.0f * (pq.x * pq.y + pq.z * pq.w); + pout.m[0][2] = 2.0f * (pq.x * pq.z - pq.y * pq.w); + pout.m[1][0] = 2.0f * (pq.x * pq.y - pq.z * pq.w); + pout.m[1][1] = 1.0f - 2.0f * (pq.x * pq.x + pq.z * pq.z); + pout.m[1][2] = 2.0f * (pq.y * pq.z + pq.x * pq.w); + pout.m[2][0] = 2.0f * (pq.x * pq.z + pq.y * pq.w); + pout.m[2][1] = 2.0f * (pq.y * pq.z - pq.x * pq.w); + pout.m[2][2] = 1.0f - 2.0f * (pq.x * pq.x + pq.y * pq.y); +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around the x-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationX(DXMatrix &pout, float angle) { + DXMatrixIdentity(pout); + //--- + pout.m[1][1] = (float)cos(angle); + pout.m[2][2] = (float)cos(angle); + pout.m[1][2] = (float)sin(angle); + pout.m[2][1] = -(float)sin(angle); +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around the y-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationY(DXMatrix &pout, float angle) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = (float)cos(angle); + pout.m[2][2] = (float)cos(angle); + pout.m[0][2] = -(float)sin(angle); + pout.m[2][0] = (float)sin(angle); +} +//+------------------------------------------------------------------+ +//| Builds a matrix with a specified yaw, pitch, and roll. | +//+------------------------------------------------------------------+ +//| The order of transformations is roll first, then pitch, then yaw.| +//| Relative to the object's local coordinate axis, this is | +//| equivalent to rotation around the z-axis, followed by rotation | +//| around the x-axis, followed by rotation around the y-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationYawPitchRoll(DXMatrix &out, float yaw, float pitch, float roll) { + float sroll = (float)sin(roll); + float croll = (float)cos(roll); + float spitch = (float)sin(pitch); + float cpitch = (float)cos(pitch); + float syaw = (float)sin(yaw); + float cyaw = (float)cos(yaw); + //--- + out.m[0][0] = sroll * spitch * syaw + croll * cyaw; + out.m[0][1] = sroll * cpitch; + out.m[0][2] = sroll * spitch * cyaw - croll * syaw; + out.m[0][3] = 0.0f; + out.m[1][0] = croll * spitch * syaw - sroll * cyaw; + out.m[1][1] = croll * cpitch; + out.m[1][2] = croll * spitch * cyaw + sroll * syaw; + out.m[1][3] = 0.0f; + out.m[2][0] = cpitch * syaw; + out.m[2][1] = -spitch; + out.m[2][2] = cpitch * cyaw; + out.m[2][3] = 0.0f; + out.m[3][0] = 0.0f; + out.m[3][1] = 0.0f; + out.m[3][2] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around the z-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationZ(DXMatrix &pout, float angle) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = (float)cos(angle); + pout.m[1][1] = (float)cos(angle); + pout.m[0][1] = (float)sin(angle); + pout.m[1][0] = -(float)sin(angle); +} +//+------------------------------------------------------------------+ +//| Builds a matrix that scales along the x-axis, | +//| the y-axis,and the z-axis. | +//+------------------------------------------------------------------+ +void DXMatrixScaling(DXMatrix &pout, float sx, float sy, float sz) { + DXMatrixIdentity(pout); + pout.m[0][0] = sx; + pout.m[1][1] = sy; + pout.m[2][2] = sz; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that flattens geometry into a plane. | +//+------------------------------------------------------------------+ +//| The DXMatrixShadow function flattens geometry into a plane, as | +//| if casting a shadow from a light. | +//| This function uses the following formula to compute the returned | +//| matrix. | +//| | +//| P = normalize(Plane); | +//| L = Light; | +//| d = -dot(P,L) | +//| | +//| P.a * L.x + d P.a * L.y P.a * L.z P.a * L.w | +//| P.b * L.x P.b * L.y + d P.b * L.z P.b * L.w | +//| P.c * L.x P.c * L.y P.c * L.z + d P.c * L.w | +//| P.d * L.x P.d * L.y P.d * L.z P.d * L.w + d | +//| | +//| If the light's w-component is 0, the ray from the origin to the | +//| light represents a directional light. If it is 1,the light is | +//| a point light. | +//+------------------------------------------------------------------+ +void DXMatrixShadow(DXMatrix &pout, const DXVector4 &plight, const DXPlane &pplane) { + DXPlane Nplane; + DXPlaneNormalize(Nplane, pplane); + float dot = DXPlaneDot(Nplane, plight); + //--- + pout.m[0][0] = dot - Nplane.a * plight.x; + pout.m[0][1] = -Nplane.a * plight.y; + pout.m[0][2] = -Nplane.a * plight.z; + pout.m[0][3] = -Nplane.a * plight.w; + pout.m[1][0] = -Nplane.b * plight.x; + pout.m[1][1] = dot - Nplane.b * plight.y; + pout.m[1][2] = -Nplane.b * plight.z; + pout.m[1][3] = -Nplane.b * plight.w; + pout.m[2][0] = -Nplane.c * plight.x; + pout.m[2][1] = -Nplane.c * plight.y; + pout.m[2][2] = dot - Nplane.c * plight.z; + pout.m[2][3] = -Nplane.c * plight.w; + pout.m[3][0] = -Nplane.d * plight.x; + pout.m[3][1] = -Nplane.d * plight.y; + pout.m[3][2] = -Nplane.d * plight.z; + pout.m[3][3] = dot - Nplane.d * plight.w; +} +//+------------------------------------------------------------------+ +//| Builds a transformation matrix. | +//+------------------------------------------------------------------+ +//| This function calculates the transformation matrix with the | +//| following formula, with matrix concatenation evaluated | +//| in left-to-right order: | +//| | +//| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | +//| | +//| where: | +//| Mout = output matrix (pOut) | +//| Msc = scaling center matrix (pScalingCenter) | +//| Msr = scaling rotation matrix (pScalingRotation) | +//| Ms = scaling matrix (pScaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (pRotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixTransformation(DXMatrix &pout, const DXVector3 &pscalingcenter, const DXQuaternion &pscalingrotation, + const DXVector3 &pscaling, const DXVector3 &protationcenter, const DXQuaternion &protation, + const DXVector3 &ptranslation) { + DXMatrix m1, m2, m3, m4, m5, m6, m7; + DXQuaternion prc; + DXVector3 psc, pt; + //--- pscalingcenter + psc.x = pscalingcenter.x; + psc.y = pscalingcenter.y; + psc.z = pscalingcenter.z; + //--- protationcenter + prc.x = protationcenter.x; + prc.y = protationcenter.y; + prc.z = protationcenter.z; + //--- ptranslation + pt.x = ptranslation.x; + pt.y = ptranslation.y; + pt.z = ptranslation.z; + DXMatrixTranslation(m1, -psc.x, -psc.y, -psc.z); + //--- + DXQuaternion temp; + DXMatrixRotationQuaternion(m4, pscalingrotation); + temp.w = pscalingrotation.w; + temp.x = -pscalingrotation.x; + temp.y = -pscalingrotation.y; + temp.z = -pscalingrotation.z; + DXMatrixRotationQuaternion(m2, temp); + //--- pscaling + DXMatrixScaling(m3, pscaling.x, pscaling.y, pscaling.z); + //--- protation + DXMatrixRotationQuaternion(m6, protation); + //--- + DXMatrixTranslation(m5, psc.x - prc.x, psc.y - prc.y, psc.z - prc.z); + DXMatrixTranslation(m7, prc.x + pt.x, prc.y + pt.y, prc.z + pt.z); + DXMatrixMultiply(m1, m1, m2); + DXMatrixMultiply(m1, m1, m3); + DXMatrixMultiply(m1, m1, m4); + DXMatrixMultiply(m1, m1, m5); + DXMatrixMultiply(m1, m1, m6); + DXMatrixMultiply(pout, m1, m7); +} +//+------------------------------------------------------------------+ +//| Builds a 2D transformation matrix that represents | +//| transformations in the xy plane. | +//+------------------------------------------------------------------+ +//| This function calculates the transformation matrix with the | +//| following formula, with matrix concatenation evaluated | +//| in left-to-right order: | +//| | +//| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | +//| | +//| where: | +//| Mout = output matrix (pOut) | +//| Msc = scaling center matrix (pScalingCenter) | +//| Msr = scaling rotation matrix (pScalingRotation) | +//| Ms = scaling matrix (pScaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (Rotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixTransformation2D(DXMatrix &pout, const DXVector2 &pscalingcenter, float scalingrotation, + const DXVector2 &pscaling, const DXVector2 &protationcenter, float rotation, + const DXVector2 &ptranslation) { + DXQuaternion rot, sca_rot; + DXVector3 rot_center, sca, sca_center, trans; + //--- pscalingcenter + sca_center.x = pscalingcenter.x; + sca_center.y = pscalingcenter.y; + sca_center.z = 0.0f; + //--- pscaling + sca.x = pscaling.x; + sca.y = pscaling.y; + sca.z = 1.0f; + //--- protationcenter + rot_center.x = protationcenter.x; + rot_center.y = protationcenter.y; + rot_center.z = 0.0f; + //--- ptranslation + trans.x = ptranslation.x; + trans.y = ptranslation.y; + trans.z = 0.0f; + //--- + rot.w = (float)cos(rotation / 2.0f); + rot.x = 0.0f; + rot.y = 0.0f; + rot.z = (float)sin(rotation / 2.0f); + //--- + sca_rot.w = (float)cos(scalingrotation / 2.0f); + sca_rot.x = 0.0f; + sca_rot.y = 0.0f; + sca_rot.z = (float)sin(scalingrotation / 2.0f); + DXMatrixTransformation(pout, sca_center, sca_rot, sca, rot_center, rot, trans); +} +//+------------------------------------------------------------------+ +//| Builds a matrix using the specified offsets. | +//+------------------------------------------------------------------+ +void DXMatrixTranslation(DXMatrix &pout, float x, float y, float z) { + DXMatrixIdentity(pout); + //--- + pout.m[3][0] = x; + pout.m[3][1] = y; + pout.m[3][2] = z; +} +//+------------------------------------------------------------------+ +//| Returns the matrix transpose of a matrix. | +//+------------------------------------------------------------------+ +void DXMatrixTranspose(DXMatrix &pout, const DXMatrix &pm) { + const DXMatrix m = pm; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) pout.m[i][j] = m.m[j][i]; +} +//+------------------------------------------------------------------+ +//| Computes the dot product of a plane and a 4D vector. | +//+------------------------------------------------------------------+ +float DXPlaneDot(const DXPlane &p1, const DXVector4 &p2) { + return (p1.a * p2.x + p1.b * p2.y + p1.c * p2.z + p1.d * p2.w); +} +//+------------------------------------------------------------------+ +//| Computes the dot product of a plane and a 3D vector. | +//| The w parameter of the vector is assumed to be 1. | +//+------------------------------------------------------------------+ +float DXPlaneDotCoord(const DXPlane &pp, const DXVector4 &pv) { + return (pp.a * pv.x + pp.b * pv.y + pp.c * pv.z + pp.d); +} +//+------------------------------------------------------------------+ +//| Computes the dot product of a plane and a 3D vector. | +//| The w parameter of the vector is assumed to be 0. | +//+------------------------------------------------------------------+ +float DXPlaneDotNormal(const DXPlane &pp, const DXVector4 &pv) { return (pp.a * pv.x + pp.b * pv.y + pp.c * pv.z); } +//+------------------------------------------------------------------+ +//| Constructs a plane from a point and a normal. | +//+------------------------------------------------------------------+ +void DXPlaneFromPointNormal(DXPlane &pout, const DXVector3 &pvpoint, const DXVector3 &pvnormal) { + pout.a = pvnormal.x; + pout.b = pvnormal.y; + pout.c = pvnormal.z; + pout.d = -DXVec3Dot(pvpoint, pvnormal); +} +//+------------------------------------------------------------------+ +//| Constructs a plane from three points. | +//+------------------------------------------------------------------+ +void DXPlaneFromPoints(DXPlane &pout, const DXVector3 &pv1, const DXVector3 &pv2, const DXVector3 &pv3) { + DXVector3 edge1, edge2, normal, Nnormal; + //--- + edge1.x = 0.0f; + edge1.y = 0.0f; + edge1.z = 0.0f; + edge2.x = 0.0f; + edge2.y = 0.0f; + edge2.z = 0.0f; + //--- + DXVec3Subtract(edge1, pv2, pv1); + DXVec3Subtract(edge2, pv3, pv1); + DXVec3Cross(normal, edge1, edge2); + DXVec3Normalize(Nnormal, normal); + DXPlaneFromPointNormal(pout, pv1, Nnormal); +} +//+------------------------------------------------------------------+ +//| Finds the intersection between a plane and a line. | +//| If the line is parallel to the plane, null vector is returned. | +//+------------------------------------------------------------------+ +void DXPlaneIntersectLine(DXVector3 &pout, const DXPlane &pp, const DXVector3 &pv1, const DXVector3 &pv2) { + DXVector3 direction, normal; + normal.x = pp.a; + normal.y = pp.b; + normal.z = pp.c; + direction.x = pv2.x - pv1.x; + direction.y = pv2.y - pv1.y; + direction.z = pv2.z - pv1.z; + //--- + float dot = DXVec3Dot(normal, direction); + if (!dot) { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + } + float temp = (pp.d + DXVec3Dot(normal, pv1)) / dot; + pout.x = pv1.x - temp * direction.x; + pout.y = pv1.y - temp * direction.y; + pout.z = pv1.z - temp * direction.z; +} +//+------------------------------------------------------------------+ +//| Normalizes the plane coefficients so that the plane normal | +//| has unit length. | +//| This function normalizes a plane so that |a,b,c| == 1. | +//+------------------------------------------------------------------+ +void DXPlaneNormalize(DXPlane &out, const DXPlane &p) { + float norm = (float)sqrt(p.a * p.a + p.b * p.b + p.c * p.c); + if (norm) { + out.a = p.a / norm; + out.b = p.b / norm; + out.c = p.c / norm; + out.d = p.d / norm; + } else { + out.a = 0.0f; + out.b = 0.0f; + out.c = 0.0f; + out.d = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Scale the plane with the given scaling factor. | +//+------------------------------------------------------------------+ +void DXPlaneScale(DXPlane &pout, const DXPlane &p, float s) { + pout.a = p.a * s; + pout.b = p.b * s; + pout.c = p.c * s; + pout.d = p.d * s; +}; +//+------------------------------------------------------------------+ +//| Transforms a plane by a matrix. | +//| The input matrix is the inverse transpose of the actual | +//| transformation. | +//+------------------------------------------------------------------+ +void DXPlaneTransform(DXPlane &pout, const DXPlane &pplane, const DXMatrix &pm) { + DXPlane plane = pplane; + //--- + pout.a = pm.m[0][0] * plane.a + pm.m[1][0] * plane.b + pm.m[2][0] * plane.c + pm.m[3][0] * plane.d; + pout.b = pm.m[0][1] * plane.a + pm.m[1][1] * plane.b + pm.m[2][1] * plane.c + pm.m[3][1] * plane.d; + pout.c = pm.m[0][2] * plane.a + pm.m[1][2] * plane.b + pm.m[2][2] * plane.c + pm.m[3][2] * plane.d; + pout.d = pm.m[0][3] * plane.a + pm.m[1][3] * plane.b + pm.m[2][3] * plane.c + pm.m[3][3] * plane.d; +} +//+------------------------------------------------------------------+ +//| Adds two spherical harmonic (SH) vectors; in other words, | +//| out[i] = a[i] + b[i]. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) is stored | +//| at memory location l^2 + m + l,where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHAdd(float &out[], int order, const float &a[], const float &b[]) { + for (int i = 0; i < order * order; i++) out[i] = a[i] + b[i]; +} +//+------------------------------------------------------------------+ +//| Computes the dot product of two spherical harmonic (SH) vectors. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) is stored | +//| at memory location l^2 + m + l,where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l,inclusive. | +//+------------------------------------------------------------------+ +float DXSHDot(int order, const float &a[], const float &b[]) { + float s = a[0] * b[0]; + for (int i = 1; i < order * order; i++) s += a[i] * b[i]; + //--- + return (s); +} +//+------------------------------------------------------------------+ +//| weightedcapintegrale | +//+------------------------------------------------------------------+ +void weightedcapintegrale(float &out[], uint order, float angle) { + float coeff[3]; + coeff[0] = (float)cos(angle); + + out[0] = 2.0f * DX_PI * (1.0f - coeff[0]); + out[1] = DX_PI * (float)sin(angle) * (float)sin(angle); + if (order <= 2) return; + + out[2] = coeff[0] * out[1]; + if (order == 3) return; + + coeff[1] = coeff[0] * coeff[0]; + coeff[2] = coeff[1] * coeff[1]; + + out[3] = DX_PI * (-1.25f * coeff[2] + 1.5f * coeff[1] - 0.25f); + if (order == 4) return; + + out[4] = -0.25f * DX_PI * coeff[0] * (7.0f * coeff[2] - 10.0f * coeff[1] + 3.0f); + if (order == 5) return; + + out[5] = DX_PI * (-2.625f * coeff[2] * coeff[1] + 4.375f * coeff[2] - 1.875f * coeff[1] + 0.125f); +} +//+------------------------------------------------------------------+ +//| Evaluates a light that is a cone of constant intensity | +//| and returns spectral spherical harmonic (SH) data. | +//+------------------------------------------------------------------+ +//| Evaluates a light that is a cone of constant intensity and | +//| returns spectral SH data. | +//| The output vector is computed so that if the intensity ratio | +//| R/G/B is equal to 1, the exit radiance of a point | +//| directly under the light (oriented in the cone direction | +//| on a diffuse object with an albedo of 1) would be 1.0. | +//| This will compute three spectral samples; | +//| rout[], gout[] and bout[] will be computed. | +//+------------------------------------------------------------------+ +int DXSHEvalConeLight(int order, const DXVector3 &dir, float radius, float Rintensity, float Gintensity, + float Bintensity, float &rout[], float &gout[], float &bout[]) { + float cap[6]; + //--- + if (radius <= 0.0f) + return (DXSHEvalDirectionalLight(order, dir, Rintensity, Gintensity, Bintensity, rout, gout, bout)); + //--- + float clamped_angle = (radius > DX_PI / 2.0f) ? (DX_PI / 2.0f) : radius; + float norm = (float)sin(clamped_angle) * (float)sin(clamped_angle); + if (order > DXSH_MAXORDER) { + //--- order clamped at DXSH_MAXORDER + order = DXSH_MAXORDER; + } + //--- + weightedcapintegrale(cap, order, radius); + DXSHEvalDirection(rout, order, dir); + //--- + for (int i = 0; i < order; i++) { + float scale = cap[i] / norm; + for (int j = 0; j < 2 * i + 1; j++) { + int index = i * i + j; + float temp = rout[index] * scale; + rout[index] = temp * Rintensity; + gout[index] = temp * Gintensity; + bout[index] = temp * Bintensity; + } + } + return (0); +} +//+------------------------------------------------------------------+ +//| Evaluates the spherical harmonic (SH) basis functions | +//| from an input direction vector. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) is stored | +//| at memory location l^2 + m + l, where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHEvalDirection(float &out[], int order, const DXVector3 &dir) { + const float dirxx = dir.x * dir.x; + const float dirxy = dir.x * dir.y; + const float dirxz = dir.x * dir.z; + const float diryy = dir.y * dir.y; + const float diryz = dir.y * dir.z; + const float dirzz = dir.z * dir.z; + const float dirxxxx = dirxx * dirxx; + const float diryyyy = diryy * diryy; + const float dirzzzz = dirzz * dirzz; + const float dirxyxy = dirxy * dirxy; + //--- + if ((order < DXSH_MINORDER) || (order > DXSH_MAXORDER)) return; + + out[0] = 0.5f / (float)sqrt(DX_PI); + out[1] = -0.5f / (float)sqrt(DX_PI / 3.0f) * dir.y; + out[2] = 0.5f / (float)sqrt(DX_PI / 3.0f) * dir.z; + out[3] = -0.5f / (float)sqrt(DX_PI / 3.0f) * dir.x; + if (order == 2) return; + + out[4] = 0.5f / (float)sqrt(DX_PI / 15.0f) * dirxy; + out[5] = -0.5f / (float)sqrt(DX_PI / 15.0f) * diryz; + out[6] = 0.25f / (float)sqrt(DX_PI / 5.0f) * (3.0f * dirzz - 1.0f); + out[7] = -0.5f / (float)sqrt(DX_PI / 15.0f) * dirxz; + out[8] = 0.25f / (float)sqrt(DX_PI / 15.0f) * (dirxx - diryy); + if (order == 3) return; + + out[9] = -(float)sqrt(70.0f / DX_PI) / 8.0f * dir.y * (3.0f * dirxx - diryy); + out[10] = (float)sqrt(105.0f / DX_PI) / 2.0f * dirxy * dir.z; + out[11] = -(float)sqrt(42.0f / DX_PI) / 8.0f * dir.y * (-1.0f + 5.0f * dirzz); + out[12] = (float)sqrt(7.0f / DX_PI) / 4.0f * dir.z * (5.0f * dirzz - 3.0f); + out[13] = (float)sqrt(42.0f / DX_PI) / 8.0f * dir.x * (1.0f - 5.0f * dirzz); + out[14] = (float)sqrt(105.0f / DX_PI) / 4.0f * dir.z * (dirxx - diryy); + out[15] = -(float)sqrt(70.0f / DX_PI) / 8.0f * dir.x * (dirxx - 3.0f * diryy); + if (order == 4) return; + + out[16] = 0.75f * float(sqrt(35.0f / DX_PI)) * dirxy * (dirxx - diryy); + out[17] = 3.0f * dir.z * out[9]; + out[18] = 0.75f * (float)sqrt(5.0f / DX_PI) * dirxy * (7.0f * dirzz - 1.0f); + out[19] = 0.375f * (float)sqrt(10.0f / DX_PI) * diryz * (3.0f - 7.0f * dirzz); + out[20] = 3.0f / (16.0f * (float)sqrt(DX_PI)) * (35.0f * dirzzzz - 30.f * dirzz + 3.0f); + out[21] = 0.375f * (float)sqrt(10.0f / DX_PI) * dirxz * (3.0f - 7.0f * dirzz); + out[22] = 0.375f * (float)sqrt(5.0f / DX_PI) * (dirxx - diryy) * (7.0f * dirzz - 1.0f); + out[23] = 3.0f * dir.z * out[15]; + out[24] = 3.0f / 16.0f * float(sqrt(35.0f / DX_PI)) * (dirxxxx - 6.0f * dirxyxy + diryyyy); + if (order == 5) return; + + out[25] = -3.0f / 32.0f * (float)sqrt(154.0f / DX_PI) * dir.y * (5.0f * dirxxxx - 10.0f * dirxyxy + diryyyy); + out[26] = 0.75f * (float)sqrt(385.0f / DX_PI) * dirxy * dir.z * (dirxx - diryy); + out[27] = (float)sqrt(770.0f / DX_PI) / 32.0f * dir.y * (3.0f * dirxx - diryy) * (1.0f - 9.0f * dirzz); + out[28] = (float)sqrt(1155.0f / DX_PI) / 4.0f * dirxy * dir.z * (3.0f * dirzz - 1.0f); + out[29] = (float)sqrt(165.0f / DX_PI) / 16.0f * dir.y * (14.0f * dirzz - 21.0f * dirzzzz - 1.0f); + out[30] = (float)sqrt(11.0f / DX_PI) / 16.0f * dir.z * (63.0f * dirzzzz - 70.0f * dirzz + 15.0f); + out[31] = (float)sqrt(165.0f / DX_PI) / 16.0f * dir.x * (14.0f * dirzz - 21.0f * dirzzzz - 1.0f); + out[32] = (float)sqrt(1155.0f / DX_PI) / 8.0f * dir.z * (dirxx - diryy) * (3.0f * dirzz - 1.0f); + out[33] = (float)sqrt(770.0f / DX_PI) / 32.0f * dir.x * (dirxx - 3.0f * diryy) * (1.0f - 9.0f * dirzz); + out[34] = 3.0f / 16.0f * (float)sqrt(385.0f / DX_PI) * dir.z * (dirxxxx - 6.0f * dirxyxy + diryyyy); + out[35] = -3.0f / 32.0f * (float)sqrt(154.0f / DX_PI) * dir.x * (dirxxxx - 10.0f * dirxyxy + 5.0f * diryyyy); +} +//+------------------------------------------------------------------+ +//| Evaluates a directional light and | +//| returns spectral spherical harmonic (SH) data. | +//+------------------------------------------------------------------+ +//| The output vector is computed so that if the intensity ratio | +//| R/G/B is equal to 1 ,the resulting exit radiance of a point | +//| directly under the light on a diffuse object with an albedo | +//| of 1 would be 1.0. This will compute three spectral samples; | +//| rout[], gout[] and bout[] will be returned. | +//+------------------------------------------------------------------+ +int DXSHEvalDirectionalLight(int order, const DXVector3 &dir, float Rintensity, float Gintensity, float Bintensity, + float &rout[], float &gout[], float &bout[]) { + float s = 0.75f; + if (order > 2) s += 5.0f / 16.0f; + if (order > 4) s -= 3.0f / 32.0f; + s /= DX_PI; + + DXSHEvalDirection(rout, order, dir); + for (int j = 0; j < order * order; j++) { + float temp = rout[j] / s; + rout[j] = Rintensity * temp; + gout[j] = Gintensity * temp; + bout[j] = Bintensity * temp; + } + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Evaluates a light that is a linear interpolation | +//| between two colors over the sphere. | +//+------------------------------------------------------------------+ +//| The interpolation is done linearly between the two points, | +//| not over the surface of the sphere (that is, if the axis was | +//| (0,0,1) it is linear in Z, not in the azimuthal angle). | +//| The resulting spherical lighting function is normalized so that | +//| a point on a perfectly diffuse surface with no shadowing | +//| and a normal pointed in the direction pDir would result in exit | +//| radiance with a value of 1 (if the top color was white | +//| and the bottom color was black). This is a very simple model | +//| where Top represents the intensity of the "sky" | +//| and Bottom represents the intensity of the "ground". | +//+------------------------------------------------------------------+ +int DXSHEvalHemisphereLight(int order, const DXVector3 &dir, DXColor &top, DXColor &bottom, float &rout[], + float &gout[], float &bout[]) { + float a[2], temp[4]; + DXSHEvalDirection(temp, 2, dir); + //--- rout + a[0] = (top.r + bottom.r) * 3.0f * DX_PI; + a[1] = (top.r - bottom.r) * DX_PI; + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) + if (i < 2) + rout[i * i + j] = temp[i * i + j] * a[i]; + else + rout[i * i + j] = 0.0f; + //--- gout + a[0] = (top.g + bottom.g) * 3.0f * DX_PI; + a[1] = (top.g - bottom.g) * DX_PI; + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) + if (i < 2) + gout[i * i + j] = temp[i * i + j] * a[i]; + else + gout[i * i + j] = 0.0f; + //--- bout + a[0] = (top.b + bottom.b) * 3.0f * DX_PI; + a[1] = (top.b - bottom.b) * DX_PI; + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) + if (i < 2) + bout[i * i + j] = temp[i * i + j] * a[i]; + else + bout[i * i + j] = 0.0f; + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Evaluates a spherical light and returns | +//| spectral spherical harmonic (SH) data. | +//+------------------------------------------------------------------+ +//| There is no normalization of the intensity of the light like | +//| there is for directional lights, so care has to be taken when | +//| specifying the intensities. | +//| This will compute three spectral samples; | +//| rout[], gout[], bout[] will be returned. | +//+------------------------------------------------------------------+ +int DXSHEvalSphericalLight(int order, const DXVector3 &dir, float radius, float Rintensity, float Gintensity, + float Bintensity, float &rout[], float &gout[], float &bout[]) { + DXVector3 normal; + float cap[6]; + //--- check order + if (order > DXSH_MAXORDER) order = DXSH_MAXORDER; + //--- check radius + if (radius < 0.0f) radius = -radius; + + float dist = DXVec3Length(dir); + float clamped_angle = (dist <= radius) ? DX_PI / 2.0f : (float)asin(radius / dist); + + weightedcapintegrale(cap, order, clamped_angle); + DXVec3Normalize(normal, dir); + DXSHEvalDirection(rout, order, normal); + + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) { + int index = i * i + j; + float temp = rout[index] * cap[i]; + rout[index] = temp * Rintensity; + gout[index] = temp * Gintensity; + bout[index] = temp * Bintensity; + } + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Computes the product of two functions represented | +//| using Spherical Harmonics (f and g). | +//+------------------------------------------------------------------+ +//| The order is a number between 2 and 6 inclusive. | +//| So it's the same for the several functions: | +//| DXSHMultiply2, DXSHMultiply3, ... DXSHMultiply6. | +//| | +//| Computes the product of two functions represented | +//| using SH (f and g),where | +//| out[i] = int(y_i(s) * f(s) * g(s)), | +//| where | +//| y_i(s) is the ith SH basis function, | +//| f(s) and g(s) are SH functions (sum_i(y_i(s)*c_i)). | +//| The order determines the lengths of the arrays, where there | +//| should always be l^2 coefficients. | +//| | +//| In general the product of two SH functions of order l generates | +//| an SH function of order 2*l - 1, but the results are truncated. | +//| | +//| This means that the product commutes (f*g == g*f) | +//| but doesn't associate (f*(g*h) != (f*g)*h. | +//+------------------------------------------------------------------+ +void DXSHMultiply2(float &out[], const float &a[], const float &b[]) { + float ta = 0.28209479f * a[0]; + float tb = 0.28209479f * b[0]; + out[0] = 0.28209479f * DXSHDot(2, a, b); + out[1] = ta * b[1] + tb * a[1]; + out[2] = ta * b[2] + tb * a[2]; + out[3] = ta * b[3] + tb * a[3]; +} +//+------------------------------------------------------------------+ +//| Computes the product of two functions represented using | +//| Spherical Harmonics (f and g). Both functions are of order N=3. | +//+------------------------------------------------------------------+ +//| The order is a number between 2 and 6 inclusive. | +//| So it's the same for the several functions: | +//| DXSHMultiply2, DXSHMultiply3, ... DXSHMultiply6. | +//| | +//| Computes the product of two functions represented | +//| using SH (f and g),where | +//| out[i] = int(y_i(s) * f(s) * g(s)), | +//| where | +//| y_i(s) is the ith SH basis function, | +//| f(s) and g(s) are SH functions (sum_i(y_i(s)*c_i)). | +//| The order determines the lengths of the arrays,where there | +//| should always be l^2 coefficients. | +//| | +//| In general the product of two SH functions of order l generates | +//| an SH function of order 2*l - 1, but the results are truncated. | +//| | +//| This means that the product commutes (f*g == g*f) | +//| but doesn't associate (f*(g*h) != (f*g)*h. | +//+------------------------------------------------------------------+ +void DXSHMultiply3(float &out[], const float &a[], const float &b[]) { + out[0] = 0.28209479f * a[0] * b[0]; + float ta = 0.28209479f * a[0] - 0.12615663f * a[6] - 0.21850969f * a[8]; + float tb = 0.28209479f * b[0] - 0.12615663f * b[6] - 0.21850969f * b[8]; + out[1] = ta * b[1] + tb * a[1]; + float t = a[1] * b[1]; + out[0] += 0.28209479f * t; + out[6] = -0.12615663f * t; + out[8] = -0.21850969f * t; + + ta = 0.21850969f * a[5]; + tb = 0.21850969f * b[5]; + out[1] += ta * b[2] + tb * a[2]; + out[2] = ta * b[1] + tb * a[1]; + t = a[1] * b[2] + a[2] * b[1]; + out[5] = 0.21850969f * t; + + ta = 0.21850969f * a[4]; + tb = 0.21850969f * b[4]; + out[1] += ta * b[3] + tb * a[3]; + out[3] = ta * b[1] + tb * a[1]; + t = a[1] * b[3] + a[3] * b[1]; + out[4] = 0.21850969f * t; + + ta = 0.28209480f * a[0] + 0.25231326f * a[6]; + tb = 0.28209480f * b[0] + 0.25231326f * b[6]; + out[2] += ta * b[2] + tb * a[2]; + t = a[2] * b[2]; + out[0] += 0.28209480f * t; + out[6] += 0.25231326f * t; + + ta = 0.21850969f * a[7]; + tb = 0.21850969f * b[7]; + out[2] += ta * b[3] + tb * a[3]; + out[3] += ta * b[2] + tb * a[2]; + t = a[2] * b[3] + a[3] * b[2]; + out[7] = 0.21850969f * t; + + ta = 0.28209479f * a[0] - 0.12615663f * a[6] + 0.21850969f * a[8]; + tb = 0.28209479f * b[0] - 0.12615663f * b[6] + 0.21850969f * b[8]; + out[3] += ta * b[3] + tb * a[3]; + t = a[3] * b[3]; + out[0] += 0.28209479f * t; + out[6] -= 0.12615663f * t; + out[8] += 0.21850969f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[4] += ta * b[4] + tb * a[4]; + t = a[4] * b[4]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; + + ta = 0.15607835f * a[7]; + tb = 0.15607835f * b[7]; + out[4] += ta * b[5] + tb * a[5]; + out[5] += ta * b[4] + tb * a[4]; + t = a[4] * b[5] + a[5] * b[4]; + out[7] += 0.15607835f * t; + + ta = 0.28209479f * a[0] + 0.09011188f * a[6] - 0.15607835f * a[8]; + tb = 0.28209479f * b[0] + 0.09011188f * b[6] - 0.15607835f * b[8]; + out[5] += ta * b[5] + tb * a[5]; + t = a[5] * b[5]; + out[0] += 0.28209479f * t; + out[6] += 0.09011188f * t; + out[8] -= 0.15607835f * t; + + ta = 0.28209480f * a[0]; + tb = 0.28209480f * b[0]; + out[6] += ta * b[6] + tb * a[6]; + t = a[6] * b[6]; + out[0] += 0.28209480f * t; + out[6] += 0.18022376f * t; + + ta = 0.28209479f * a[0] + 0.09011188f * a[6] + 0.15607835f * a[8]; + tb = 0.28209479f * b[0] + 0.09011188f * b[6] + 0.15607835f * b[8]; + out[7] += ta * b[7] + tb * a[7]; + t = a[7] * b[7]; + out[0] += 0.28209479f * t; + out[6] += 0.09011188f * t; + out[8] += 0.15607835f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[8] += ta * b[8] + tb * a[8]; + t = a[8] * b[8]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; +} +//+------------------------------------------------------------------+ +//| Computes the product of two functions represented using | +//| Spherical Harmonics (f and g). Both functions are of order N=4. | +//+------------------------------------------------------------------+ +//| The order is a number between 2 and 6 inclusive. | +//| So it's the same for the several functions: | +//| DXSHMultiply2, DXSHMultiply3, ... DXSHMultiply6. | +//| | +//| Computes the product of two functions represented | +//| using SH (f and g), where | +//| out[i] = int(y_i(s) * f(s) * g(s)), | +//| where | +//| y_i(s) is the ith SH basis function, | +//| f(s) and g(s) are SH functions (sum_i(y_i(s)*c_i)). | +//| The order determines the lengths of the arrays,where there | +//| should always be l^2 coefficients. | +//| | +//| In general the product of two SH functions of order l generates | +//| an SH function of order 2*l - 1, but the results are truncated. | +//| | +//| This means that the product commutes (f*g == g*f) | +//| but doesn't associate (f*(g*h) != (f*g)*h. | +//+------------------------------------------------------------------+ +void DXSHMultiply4(float &out[], const float &a[], const float &b[]) { + out[0] = 0.28209479f * a[0] * b[0]; + float ta = 0.28209479f * a[0] - 0.12615663f * a[6] - 0.21850969f * a[8]; + float tb = 0.28209479f * b[0] - 0.12615663f * b[6] - 0.21850969f * b[8]; + out[1] = ta * b[1] + tb * a[1]; + float t = a[1] * b[1]; + out[0] += 0.28209479f * t; + out[6] = -0.12615663f * t; + out[8] = -0.21850969f * t; + + ta = 0.21850969f * a[3] - 0.05839917f * a[13] - 0.22617901f * a[15]; + tb = 0.21850969f * b[3] - 0.05839917f * b[13] - 0.22617901f * b[15]; + out[1] += ta * b[4] + tb * a[4]; + out[4] = ta * b[1] + tb * a[1]; + t = a[1] * b[4] + a[4] * b[1]; + out[3] = 0.21850969f * t; + out[13] = -0.05839917f * t; + out[15] = -0.22617901f * t; + + ta = 0.21850969f * a[2] - 0.14304817f * a[12] - 0.18467439f * a[14]; + tb = 0.21850969f * b[2] - 0.14304817f * b[12] - 0.18467439f * b[14]; + out[1] += ta * b[5] + tb * a[5]; + out[5] = ta * b[1] + tb * a[1]; + t = a[1] * b[5] + a[5] * b[1]; + out[2] = 0.21850969f * t; + out[12] = -0.14304817f * t; + out[14] = -0.18467439f * t; + + ta = 0.20230066f * a[11]; + tb = 0.20230066f * b[11]; + out[1] += ta * b[6] + tb * a[6]; + out[6] += ta * b[1] + tb * a[1]; + t = a[1] * b[6] + a[6] * b[1]; + out[11] = 0.20230066f * t; + + ta = 0.22617901f * a[9] + 0.05839917f * a[11]; + tb = 0.22617901f * b[9] + 0.05839917f * b[11]; + out[1] += ta * b[8] + tb * a[8]; + out[8] += ta * b[1] + tb * a[1]; + t = a[1] * b[8] + a[8] * b[1]; + out[9] = 0.22617901f * t; + out[11] += 0.05839917f * t; + + ta = 0.28209480f * a[0] + 0.25231326f * a[6]; + tb = 0.28209480f * b[0] + 0.25231326f * b[6]; + out[2] += ta * b[2] + tb * a[2]; + t = a[2] * b[2]; + out[0] += 0.28209480f * t; + out[6] += 0.25231326f * t; + + ta = 0.24776671f * a[12]; + tb = 0.24776671f * b[12]; + out[2] += ta * b[6] + tb * a[6]; + out[6] += ta * b[2] + tb * a[2]; + t = a[2] * b[6] + a[6] * b[2]; + out[12] += 0.24776671f * t; + + ta = 0.28209480f * a[0] - 0.12615663f * a[6] + 0.21850969f * a[8]; + tb = 0.28209480f * b[0] - 0.12615663f * b[6] + 0.21850969f * b[8]; + out[3] += ta * b[3] + tb * a[3]; + t = a[3] * b[3]; + out[0] += 0.28209480f * t; + out[6] -= 0.12615663f * t; + out[8] += 0.21850969f * t; + + ta = 0.20230066f * a[13]; + tb = 0.20230066f * b[13]; + out[3] += ta * b[6] + tb * a[6]; + out[6] += ta * b[3] + tb * a[3]; + t = a[3] * b[6] + a[6] * b[3]; + out[13] += 0.20230066f * t; + + ta = 0.21850969f * a[2] - 0.14304817f * a[12] + 0.18467439f * a[14]; + tb = 0.21850969f * b[2] - 0.14304817f * b[12] + 0.18467439f * b[14]; + out[3] += ta * b[7] + tb * a[7]; + out[7] = ta * b[3] + tb * a[3]; + t = a[3] * b[7] + a[7] * b[3]; + out[2] += 0.21850969f * t; + out[12] -= 0.14304817f * t; + out[14] += 0.18467439f * t; + + ta = -0.05839917f * a[13] + 0.22617901f * a[15]; + tb = -0.05839917f * b[13] + 0.22617901f * b[15]; + out[3] += ta * b[8] + tb * a[8]; + out[8] += ta * b[3] + tb * a[3]; + t = a[3] * b[8] + a[8] * b[3]; + out[13] -= 0.05839917f * t; + out[15] += 0.22617901f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[4] += ta * b[4] + tb * a[4]; + t = a[4] * b[4]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; + + ta = 0.15607835f * a[7]; + tb = 0.15607835f * b[7]; + out[4] += ta * b[5] + tb * a[5]; + out[5] += ta * b[4] + tb * a[4]; + t = a[4] * b[5] + a[5] * b[4]; + out[7] += 0.15607835f * t; + + ta = 0.22617901f * a[3] - 0.09403160f * a[13]; + tb = 0.22617901f * b[3] - 0.09403160f * b[13]; + out[4] += ta * b[9] + tb * a[9]; + out[9] += ta * b[4] + tb * a[4]; + t = a[4] * b[9] + a[9] * b[4]; + out[3] += 0.22617901f * t; + out[13] -= 0.09403160f * t; + + ta = 0.18467439f * a[2] - 0.18806319f * a[12]; + tb = 0.18467439f * b[2] - 0.18806319f * b[12]; + out[4] += ta * b[10] + tb * a[10]; + out[10] = ta * b[4] + tb * a[4]; + t = a[4] * b[10] + a[10] * b[4]; + out[2] += 0.18467439f * t; + out[12] -= 0.18806319f * t; + + ta = -0.05839917f * a[3] + 0.14567312f * a[13] + 0.09403160f * a[15]; + tb = -0.05839917f * b[3] + 0.14567312f * b[13] + 0.09403160f * b[15]; + out[4] += ta * b[11] + tb * a[11]; + out[11] += ta * b[4] + tb * a[4]; + t = a[4] * b[11] + a[11] * b[4]; + out[3] -= 0.05839917f * t; + out[13] += 0.14567312f * t; + out[15] += 0.09403160f * t; + + ta = 0.28209479f * a[0] + 0.09011186f * a[6] - 0.15607835f * a[8]; + tb = 0.28209479f * b[0] + 0.09011186f * b[6] - 0.15607835f * b[8]; + out[5] += ta * b[5] + tb * a[5]; + t = a[5] * b[5]; + out[0] += 0.28209479f * t; + out[6] += 0.09011186f * t; + out[8] -= 0.15607835f * t; + + ta = 0.14867701f * a[14]; + tb = 0.14867701f * b[14]; + out[5] += ta * b[9] + tb * a[9]; + out[9] += ta * b[5] + tb * a[5]; + t = a[5] * b[9] + a[9] * b[5]; + out[14] += 0.14867701f * t; + + ta = 0.18467439f * a[3] + 0.11516472f * a[13] - 0.14867701f * a[15]; + tb = 0.18467439f * b[3] + 0.11516472f * b[13] - 0.14867701f * b[15]; + out[5] += ta * b[10] + tb * a[10]; + out[10] += ta * b[5] + tb * a[5]; + t = a[5] * b[10] + a[10] * b[5]; + out[3] += 0.18467439f * t; + out[13] += 0.11516472f * t; + out[15] -= 0.14867701f * t; + + ta = 0.23359668f * a[2] + 0.05947080f * a[12] - 0.11516472f * a[14]; + tb = 0.23359668f * b[2] + 0.05947080f * b[12] - 0.11516472f * b[14]; + out[5] += ta * b[11] + tb * a[11]; + out[11] += ta * b[5] + tb * a[5]; + t = a[5] * b[11] + a[11] * b[5]; + out[2] += 0.23359668f * t; + out[12] += 0.05947080f * t; + out[14] -= 0.11516472f * t; + + ta = 0.28209479f * a[0]; + tb = 0.28209479f * b[0]; + out[6] += ta * b[6] + tb * a[6]; + t = a[6] * b[6]; + out[0] += 0.28209479f * t; + out[6] += 0.18022376f * t; + + ta = 0.09011186f * a[6] + 0.28209479f * a[0] + 0.15607835f * a[8]; + tb = 0.09011186f * b[6] + 0.28209479f * b[0] + 0.15607835f * b[8]; + out[7] += ta * b[7] + tb * a[7]; + t = a[7] * b[7]; + out[6] += 0.09011186f * t; + out[0] += 0.28209479f * t; + out[8] += 0.15607835f * t; + + ta = 0.14867701f * a[9] + 0.18467439f * a[1] + 0.11516472f * a[11]; + tb = 0.14867701f * b[9] + 0.18467439f * b[1] + 0.11516472f * b[11]; + out[7] += ta * b[10] + tb * a[10]; + out[10] += ta * b[7] + tb * a[7]; + t = a[7] * b[10] + a[10] * b[7]; + out[9] += 0.14867701f * t; + out[1] += 0.18467439f * t; + out[11] += 0.11516472f * t; + + ta = 0.05947080f * a[12] + 0.23359668f * a[2] + 0.11516472f * a[14]; + tb = 0.05947080f * b[12] + 0.23359668f * b[2] + 0.11516472f * b[14]; + out[7] += ta * b[13] + tb * a[13]; + out[13] += ta * b[7] + tb * a[7]; + t = a[7] * b[13] + a[13] * b[7]; + out[12] += 0.05947080f * t; + out[2] += 0.23359668f * t; + out[14] += 0.11516472f * t; + + ta = 0.14867701f * a[15]; + tb = 0.14867701f * b[15]; + out[7] += ta * b[14] + tb * a[14]; + out[14] += ta * b[7] + tb * a[7]; + t = a[7] * b[14] + a[14] * b[7]; + out[15] += 0.14867701f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[8] += ta * b[8] + tb * a[8]; + t = a[8] * b[8]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; + + ta = -0.09403160f * a[11]; + tb = -0.09403160f * b[11]; + out[8] += ta * b[9] + tb * a[9]; + out[9] += ta * b[8] + tb * a[8]; + t = a[8] * b[9] + a[9] * b[8]; + out[11] -= 0.09403160f * t; + + ta = -0.09403160f * a[15]; + tb = -0.09403160f * b[15]; + out[8] += ta * b[13] + tb * a[13]; + out[13] += ta * b[8] + tb * a[8]; + t = a[8] * b[13] + a[13] * b[8]; + out[15] -= 0.09403160f * t; + + ta = 0.18467439f * a[2] - 0.18806319f * a[12]; + tb = 0.18467439f * b[2] - 0.18806319f * b[12]; + out[8] += ta * b[14] + tb * a[14]; + out[14] += ta * b[8] + tb * a[8]; + t = a[8] * b[14] + a[14] * b[8]; + out[2] += 0.18467439f * t; + out[12] -= 0.18806319f * t; + + ta = -0.21026104f * a[6] + 0.28209479f * a[0]; + tb = -0.21026104f * b[6] + 0.28209479f * b[0]; + out[9] += ta * b[9] + tb * a[9]; + t = a[9] * b[9]; + out[6] -= 0.21026104f * t; + out[0] += 0.28209479f * t; + + ta = 0.28209479f * a[0]; + tb = 0.28209479f * b[0]; + out[10] += ta * b[10] + tb * a[10]; + t = a[10] * b[10]; + out[0] += 0.28209479f * t; + + ta = 0.28209479f * a[0] + 0.12615663f * a[6] - 0.14567312f * a[8]; + tb = 0.28209479f * b[0] + 0.12615663f * b[6] - 0.14567312f * b[8]; + out[11] += ta * b[11] + tb * a[11]; + t = a[11] * b[11]; + out[0] += 0.28209479f * t; + out[6] += 0.12615663f * t; + out[8] -= 0.14567312f * t; + + ta = 0.28209479f * a[0] + 0.16820885f * a[6]; + tb = 0.28209479f * b[0] + 0.16820885f * b[6]; + out[12] += ta * b[12] + tb * a[12]; + t = a[12] * b[12]; + out[0] += 0.28209479f * t; + out[6] += 0.16820885f * t; + + ta = 0.28209479f * a[0] + 0.14567312f * a[8] + 0.12615663f * a[6]; + tb = 0.28209479f * b[0] + 0.14567312f * b[8] + 0.12615663f * b[6]; + out[13] += ta * b[13] + tb * a[13]; + t = a[13] * b[13]; + out[0] += 0.28209479f * t; + out[8] += 0.14567312f * t; + out[6] += 0.12615663f * t; + + ta = 0.28209479f * a[0]; + tb = 0.28209479f * b[0]; + out[14] += ta * b[14] + tb * a[14]; + t = a[14] * b[14]; + out[0] += 0.28209479f * t; + + ta = 0.28209479f * a[0] - 0.21026104f * a[6]; + tb = 0.28209479f * b[0] - 0.21026104f * b[6]; + out[15] += ta * b[15] + tb * a[15]; + t = a[15] * b[15]; + out[0] += 0.28209479f * t; + out[6] -= 0.21026104f * t; +} +//+------------------------------------------------------------------+ +//| rotate_X | +//+------------------------------------------------------------------+ +void rotate_X(float &out[], uint order, float a, float &in[]) { + out[0] = in[0]; + out[1] = a * in[2]; + out[2] = -a * in[1]; + out[3] = in[3]; + out[4] = a * in[7]; + out[5] = -in[5]; + out[6] = -0.5f * in[6] - 0.8660253882f * in[8]; + out[7] = -a * in[4]; + out[8] = -0.8660253882f * in[6] + 0.5f * in[8]; + out[9] = -a * 0.7905694842f * in[12] + a * 0.6123724580f * in[14]; + out[10] = -in[10]; + out[11] = -a * 0.6123724580f * in[12] - a * 0.7905694842f * in[14]; + out[12] = a * 0.7905694842f * in[9] + a * 0.6123724580f * in[11]; + out[13] = -0.25f * in[13] - 0.9682458639f * in[15]; + out[14] = -a * 0.6123724580f * in[9] + a * 0.7905694842f * in[11]; + out[15] = -0.9682458639f * in[13] + 0.25f * in[15]; + if (order == 4) return; + + out[16] = -a * 0.9354143739f * in[21] + a * 0.3535533845f * in[23]; + out[17] = -0.75f * in[17] + 0.6614378095f * in[19]; + out[18] = -a * 0.3535533845f * in[21] - a * 0.9354143739f * in[23]; + out[19] = 0.6614378095f * in[17] + 0.75f * in[19]; + out[20] = 0.375f * in[20] + 0.5590170026f * in[22] + 0.7395099998f * in[24]; + out[21] = a * 0.9354143739f * in[16] + a * 0.3535533845f * in[18]; + out[22] = 0.5590170026f * in[20] + 0.5f * in[22] - 0.6614378691f * in[24]; + out[23] = -a * 0.3535533845f * in[16] + a * 0.9354143739f * in[18]; + out[24] = 0.7395099998f * in[20] - 0.6614378691f * in[22] + 0.125f * in[24]; + if (order == 5) return; + + out[25] = a * 0.7015607357f * in[30] - a * 0.6846531630f * in[32] + a * 0.1976423711f * in[34]; + out[26] = -0.5f * in[26] + 0.8660253882f * in[28]; + out[27] = a * 0.5229125023f * in[30] + a * 0.3061861992f * in[32] - a * 0.7954951525f * in[34]; + out[28] = 0.8660253882f * in[26] + 0.5f * in[28]; + out[29] = a * 0.4841229022f * in[30] + a * 0.6614378691f * in[32] + a * 0.5728219748f * in[34]; + out[30] = -a * 0.7015607357f * in[25] - a * 0.5229125023f * in[27] - a * 0.4841229022f * in[29]; + out[31] = 0.125f * in[31] + 0.4050463140f * in[33] + 0.9057110548f * in[35]; + out[32] = a * 0.6846531630f * in[25] - a * 0.3061861992f * in[27] - a * 0.6614378691f * in[29]; + out[33] = 0.4050463140f * in[31] + 0.8125f * in[33] - 0.4192627370f * in[35]; + out[34] = -a * 0.1976423711f * in[25] + a * 0.7954951525f * in[27] - a * 0.5728219748f * in[29]; + out[35] = 0.9057110548f * in[31] - 0.4192627370f * in[33] + 0.0624999329f * in[35]; +} +//+------------------------------------------------------------------+ +//| Rotates the spherical harmonic (SH) vector by the given matrix. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) | +//| is stored at memory location l^2 + m + l, where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHRotate(float &out[], int order, const DXMatrix &matrix, const float &in[]) { + float alpha, beta, gamma, sinb, temp[36], temp1[36]; + out[0] = in[0]; + + if ((order > DXSH_MAXORDER) || (order < DXSH_MINORDER)) return; + + if (order <= 3) { + out[1] = matrix.m[1][1] * in[1] - matrix.m[2][1] * in[2] + matrix.m[0][1] * in[3]; + out[2] = -matrix.m[1][2] * in[1] + matrix.m[2][2] * in[2] - matrix.m[0][2] * in[3]; + out[3] = matrix.m[1][0] * in[1] - matrix.m[2][0] * in[2] + matrix.m[0][0] * in[3]; + + if (order == 3) { + float coeff[12] = {}; + coeff[0] = matrix.m[1][0] * matrix.m[0][0]; + coeff[1] = matrix.m[1][1] * matrix.m[0][1]; + coeff[2] = matrix.m[1][1] * matrix.m[2][1]; + coeff[3] = matrix.m[1][0] * matrix.m[2][0]; + coeff[4] = matrix.m[2][0] * matrix.m[2][0]; + coeff[5] = matrix.m[2][1] * matrix.m[2][1]; + coeff[6] = matrix.m[0][0] * matrix.m[2][0]; + coeff[7] = matrix.m[0][1] * matrix.m[2][1]; + coeff[8] = matrix.m[0][1] * matrix.m[0][1]; + coeff[9] = matrix.m[1][0] * matrix.m[1][0]; + coeff[10] = matrix.m[1][1] * matrix.m[1][1]; + coeff[11] = matrix.m[0][0] * matrix.m[0][0]; + + out[4] = (matrix.m[1][1] * matrix.m[0][0] + matrix.m[0][1] * matrix.m[1][0]) * in[4]; + out[4] -= (matrix.m[1][0] * matrix.m[2][1] + matrix.m[1][1] * matrix.m[2][0]) * in[5]; + out[4] += 1.7320508076f * matrix.m[2][0] * matrix.m[2][1] * in[6]; + out[4] -= (matrix.m[0][1] * matrix.m[2][0] + matrix.m[0][0] * matrix.m[2][1]) * in[7]; + out[4] += (matrix.m[0][0] * matrix.m[0][1] - matrix.m[1][0] * matrix.m[1][1]) * in[8]; + + out[5] = (matrix.m[1][1] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][1]) * in[5]; + out[5] -= (matrix.m[1][1] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][1]) * in[4]; + out[5] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][1] * in[6]; + out[5] += (matrix.m[0][2] * matrix.m[2][1] + matrix.m[0][1] * matrix.m[2][2]) * in[7]; + out[5] -= (matrix.m[0][1] * matrix.m[0][2] - matrix.m[1][1] * matrix.m[1][2]) * in[8]; + + out[6] = (matrix.m[2][2] * matrix.m[2][2] - 0.5f * (coeff[4] + coeff[5])) * in[6]; + out[6] -= (0.5773502692f * (coeff[0] + coeff[1]) - 1.1547005384f * matrix.m[1][2] * matrix.m[0][2]) * in[4]; + out[6] += (0.5773502692f * (coeff[2] + coeff[3]) - 1.1547005384f * matrix.m[1][2] * matrix.m[2][2]) * in[5]; + out[6] += (0.5773502692f * (coeff[6] + coeff[7]) - 1.1547005384f * matrix.m[0][2] * matrix.m[2][2]) * in[7]; + out[6] += (0.2886751347f * (coeff[9] - coeff[8] + coeff[10] - coeff[11]) - + 0.5773502692f * (matrix.m[1][2] * matrix.m[1][2] - matrix.m[0][2] * matrix.m[0][2])) * + in[8]; + + out[7] = (matrix.m[0][0] * matrix.m[2][2] + matrix.m[0][2] * matrix.m[2][0]) * in[7]; + out[7] -= (matrix.m[1][0] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][0]) * in[4]; + out[7] += (matrix.m[1][0] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][0]) * in[5]; + out[7] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][0] * in[6]; + out[7] -= (matrix.m[0][0] * matrix.m[0][2] - matrix.m[1][0] * matrix.m[1][2]) * in[8]; + + out[8] = 0.5f * (coeff[11] - coeff[8] - coeff[9] + coeff[10]) * in[8]; + out[8] += (coeff[0] - coeff[1]) * in[4]; + out[8] += (coeff[2] - coeff[3]) * in[5]; + out[8] += 0.86602540f * (coeff[4] - coeff[5]) * in[6]; + out[8] += (coeff[7] - coeff[6]) * in[7]; + } + return; + } + + if ((float)fabs(matrix.m[2][2]) != 1.0f) { + sinb = (float)sqrt(1.0f - matrix.m[2][2] * matrix.m[2][2]); + alpha = (float)atan2(matrix.m[2][1] / sinb, matrix.m[2][0] / sinb); + beta = (float)atan2(sinb, matrix.m[2][2]); + gamma = (float)atan2(matrix.m[1][2] / sinb, -matrix.m[0][2] / sinb); + } else { + alpha = (float)atan2(matrix.m[0][1], matrix.m[0][0]); + beta = 0.0f; + gamma = 0.0f; + } + //--- + DXSHRotateZ(temp, order, gamma, in); + rotate_X(temp1, order, 1.0f, temp); + DXSHRotateZ(temp, order, beta, temp1); + rotate_X(temp1, order, -1.0f, temp); + DXSHRotateZ(out, order, alpha, temp1); +} +//+------------------------------------------------------------------+ +//| Rotates the spherical harmonic (SH) vector | +//| in the z-axis by the given angle. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) | +//| is stored at memory location l^2 + m + l, where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHRotateZ(float &out[], int order, float angle, const float &in[]) { + int sum = 0; + float c[5], s[5]; + order = (int)fmin(fmax(order, DXSH_MINORDER), DXSH_MAXORDER); + out[0] = in[0]; + //--- + for (int i = 1; i < order; i++) { + c[i - 1] = (float)cos(i * angle); + s[i - 1] = (float)sin(i * angle); + sum += i * 2; + //--- + out[sum - i] = c[i - 1] * in[sum - i]; + out[sum - i] += s[i - 1] * in[sum + i]; + for (int j = i - 1; j > 0; j--) { + out[sum - j] = 0.0f; + out[sum - j] = c[j - 1] * in[sum - j]; + out[sum - j] += s[j - 1] * in[sum + j]; + } + out[sum] = in[sum]; + //--- + for (int j = 1; j < i; j++) { + out[sum + j] = 0.0f; + out[sum + j] = -s[j - 1] * in[sum - j]; + out[sum + j] += c[j - 1] * in[sum + j]; + } + out[sum + i] = -s[i - 1] * in[sum - i]; + out[sum + i] += c[i - 1] * in[sum + i]; + } +} +//+------------------------------------------------------------------+ +//| Scales a spherical harmonic (SH) vector; | +//| in other words, out[i] = a[i]*scale. | +//+------------------------------------------------------------------+ +void DXSHScale(float &out[], int order, const float &a[], const float scale) { + for (int i = 0; i < order * order; i++) out[i] = a[i] * scale; +} +//+---------------------------------------------------------------------+ +//| Interpolates y0 to y1 according to value from 0.0 to 1.0 | +//+---------------------------------------------------------------------+ +float DXScalarLerp(const float val1, const float val2, float s) { return ((1 - s) * val1 + s * val2); } +//+---------------------------------------------------------------------+ +//| Interpolates y0 to y1 according to value from 0.0 to 1.0 | +//+---------------------------------------------------------------------+ +float DXScalarBiasScale(const float val, const float bias, const float scale) { return ((val + bias) * scale); } +//+------------------------------------------------------------------+ diff --git a/3D/Mesh.h b/3D/Mesh.h new file mode 100644 index 000000000..2d28ddaf9 --- /dev/null +++ b/3D/Mesh.h @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics mesh. + */ + +#include "../Dict.mqh" +#include "../Refs.mqh" +#include "../Util.h" +#include "Face.h" +#include "IndexBuffer.h" +#include "Math.h" +#include "VertexBuffer.h" + +class Device; + +#define GFX_MESH_LOOKUP_PRECISION 0.001f + +// Point with a key for faster vertices' lookup by their position. +template +struct PointEntry { + T point; + long key; + + PointEntry() {} + + PointEntry(const T& _point) { + point = _point; + key = MakeKey(_point.Position[0], _point.Position[1], _point.Position[2]); + } + + bool operator==(const PointEntry& _r) { + return key == MakeKey(_r.point.Position[0], _r.point.Position[1], _r.point.Position[2]); + } + + static long MakeKey(float x, float y, float z) { + return long(x / GFX_MESH_LOOKUP_PRECISION) + 4194304 * long(y / GFX_MESH_LOOKUP_PRECISION) + + 17592186044416 * long(z / GFX_MESH_LOOKUP_PRECISION); + } +}; + +template +class Mesh : public Dynamic { + Ref vbuff; + Ref ibuff; + Face faces[]; + + public: + /** + * Constructor. + */ + Mesh() {} + + /** + * Adds a single 3 or 4-vertex face. + */ + void AddFace(Face& face) { Util::ArrayPush(faces, face, 16); } + + /** + * Returns vertex and index buffers for this mesh. + * + * @todo Buffers should be invalidated if mesh has changed. + */ + bool GetBuffers(Device* _device, VertexBuffer*& _vbuff, IndexBuffer*& _ibuff) { + if (vbuff.IsSet() && ibuff.IsSet()) { + _vbuff = vbuff.Ptr(); + _ibuff = ibuff.Ptr(); + return true; + } + + DictStruct> _points; + T _vertices[]; + unsigned int _indices[]; + int i, k; + + for (i = 0; i < ArraySize(faces); ++i) { + Face _face = faces[i]; + int _face_indices[4]; + + // Adding first triangle. + for (k = 0; k < 3; ++k) { + PointEntry point1(_face.points[k]); + _face_indices[k] = _points.IndexOf(point1); + + if (_face_indices[k] == -1) { + // Point not yet added. + _points.Push(point1); + _face_indices[k] = (int)_points.Size() - 1; + } + + Util::ArrayPush(_indices, _face_indices[k]); + } + + // Adding second triangle if needed. + if ((_face.flags & FACE_FLAGS_QUAD) == FACE_FLAGS_QUAD) { + PointEntry point2(_face.points[3]); + _face_indices[3] = _points.IndexOf(point2); + + if (_face_indices[3] == -1) { + // Point not yet added. + _points.Push(point2); + _face_indices[3] = (int)_points.Size() - 1; + } + + Util::ArrayPush(_indices, _face_indices[0]); + Util::ArrayPush(_indices, _face_indices[2]); + Util::ArrayPush(_indices, _face_indices[3]); + } + } + + ArrayResize(_vertices, _points.Size()); + + for (DictIteratorBase> iter(_points.Begin()); iter.IsValid(); ++iter) { + _vertices[iter.Index()] = iter.Value().point; + } + + string _s_vertices = "["; + + for (i = 0; i < ArraySize(_vertices); ++i) { + _s_vertices += "["; + _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position[0]) + ", " + + DoubleToString(_vertices[i].Position[1]) + "," + DoubleToString(_vertices[i].Position[2]) + " | "; + _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color[0]) + ", " + DoubleToString(_vertices[i].Color[1]) + + "," + DoubleToString(_vertices[i].Color[2]) + "," + DoubleToString(_vertices[i].Color[3]); + _s_vertices += "]"; + if (i != ArraySize(_vertices) - 1) { + _s_vertices += ", "; + } + } + + _s_vertices += "]"; + + string _s_indices = "["; + + for (i = 0; i < ArraySize(_indices); ++i) { + _s_indices += DoubleToString(_indices[i]); + if (i != ArraySize(_indices) - 1) { + _s_indices += ", "; + } + } + + _s_indices += "]"; + + Print("Vertices: ", _s_vertices); + Print("Indices: ", _s_indices); + + vbuff = _vbuff = _device.VertexBuffer(_vertices); + ibuff = _ibuff = _device.IndexBuffer(_indices); + return true; + } +}; \ No newline at end of file diff --git a/3D/Shader.h b/3D/Shader.h index 1ef91bd65..1500a1430 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -1,5 +1,33 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics shader. + */ + #include "../Refs.mqh" +// Shader type. enum ENUM_SHADER_TYPE { SHADER_TYPE_VS, SHADER_TYPE_PS, @@ -10,6 +38,7 @@ class MTDXShader; enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; +// Vertex layout used for Vertex Shaders. struct ShaderVertexLayout { string name; unsigned int index; @@ -24,6 +53,7 @@ struct ShaderVertexLayout { * Unified vertex/pixel shader. */ class Shader : public Dynamic { + // Reference to graphics device. WeakRef device; public: @@ -36,19 +66,24 @@ class Shader : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } - - template + + /** + * Sets custom input buffer for shader. + */ + template void SetCBuffer(const X& data) { // Unfortunately we can't make this method virtual. if (dynamic_cast(&this) != NULL) { // MT5's DirectX. Print("Setting CBuffer data for MT5"); ((MTDXShader*)&this).SetCBuffer(data); - } - else { + } else { Alert("Unsupported cbuffer device target"); } } - + + /** + * Selectes shader to be used by graphics device for rendering. + */ virtual void Select() = NULL; }; \ No newline at end of file diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h index cf3f600f4..8c979b384 100644 --- a/3D/VertexBuffer.h +++ b/3D/VertexBuffer.h @@ -1,6 +1,34 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics vertex buffer. + */ + #include "../Refs.mqh" class VertexBuffer : public Dynamic { + // Reference to graphics device. WeakRef device; public: @@ -13,6 +41,6 @@ class VertexBuffer : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } - + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/Dict.mqh b/Dict.mqh index 51ebffbc6..81b87a99b 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -151,6 +151,20 @@ class Dict : public DictBase { return slot.value == value; } + /** + * Returns index of dictionary's value or -1 if value doesn't exist. + */ + template <> + int IndexOf(V& value) { + for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + if (i.Value() == value) { + return (int)i.Index(); + } + } + + return -1; + } + protected: /** * Inserts value into given array of DictSlots. diff --git a/DictObject.mqh b/DictObject.mqh index 3405d3b04..4e874a63b 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -157,6 +157,20 @@ class DictObject : public DictBase { return slot.value == value; } + /** + * Returns index of dictionary's value or -1 if value doesn't exist. + */ + template <> + int IndexOf(V& value) { + for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + if (i.Value() == value) { + return (int)i.Index(); + } + } + + return -1; + } + protected: /** * Inserts value into given array of DictSlots. diff --git a/DictStruct.mqh b/DictStruct.mqh index 37196e45c..163ccd489 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -195,6 +195,20 @@ class DictStruct : public DictBase { return slot.value == value; } + /** + * Returns index of dictionary's value or -1 if value doesn't exist. + */ + template <> + int IndexOf(const V& value) { + for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + if (i.Value() == value) { + return (int)i.Index(); + } + } + + return -1; + } + protected: /** * Inserts value into given array of DictSlots. diff --git a/Util.h b/Util.h new file mode 100644 index 000000000..e562d1955 --- /dev/null +++ b/Util.h @@ -0,0 +1,46 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* + * @file + * Utility methods. + */ + +class Util { + /** + * Resizes native array and reserves space for further items by some fixed step. + */ + template + static void ArrayResize(T& _array[], int _new_size, int _resize_pool = 32) { + ::ArrayResize(_array, _new_size, (_new_size / _resize_pool + 1) * _resize_pool); + } + + /** + * Pushes item into the native array and reserves space for further items by some fixed step. + */ + template + static int ArrayPush(T& _array[], const V& _value, int _resize_pool = 32) { + Util::ArrayResize(_array, ArraySize(_array) + 1, _resize_pool); + _array[ArraySize(_array) - 1] = _value; + return ArraySize(_array) - 1; + } +}; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 9a20bfd27..6211ca9ac 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -24,111 +24,110 @@ * Test functionality of 3D visualization classes. */ +#ifdef __MQL5__ + // Resources. #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; // Includes. -#include "../3D/Frontends/MT5Frontend.h" +#include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" #include "../3D/Devices/MTDX/MTDXIndexBuffer.h" #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" +#include "../3D/Frontends/MT5Frontend.h" #include "../Test.mqh" -int OnStart() { - return OnInit(); -} +// int OnStart() { return OnInit(); } struct Vertex { float Position[3]; float Color[4]; + + Vertex() { + Color[0] = 1.0f / 65535 * rand(); + Color[1] = 1.0f / 65535 * rand(); + Color[2] = 1.0f / 65535 * rand(); + Color[3] = 1.0f; + } }; const ShaderVertexLayout VertexLayout[] = { - { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0 }, - { "COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*3 }, + {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, + {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 3}, }; -struct PSCBuffer -{ +struct PSCBuffer { DXMatrix world; DXMatrix view; DXMatrix proj; }; /** - * Implements OnStart(). + * Implements Oninit(). */ int OnInit() { Ref gfx_ptr = new MTDXDevice(); Device* gfx = gfx_ptr.Ptr(); - + gfx.Start(new MT5Frontend()); - + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); Ref _shader_p = gfx.PixelShader(ShaderSourcePS); - - Vertex vertices[]= { - { - {-0.5, -0.5, 0.0}, - { 1.0, 0.0, 0.0, 1.0}, - }, - { - {-0.5, 0.5, 0.0}, - { 0.0, 0.1, 0.0, 1.0}, - }, - { - { 0.5, 0.5, 0.0}, - { 0.0, 0.0, 1.0, 1.0}, - }, - { - { 0.5, -0.5, 0.0}, - { 0.5, 0.5, 1.0, 1.0}, - } - }; - - unsigned int indices[] = { - 0, 1, 2, - 2, 3, 0 - }; - - Ref _vbuff = gfx.VertexBuffer(vertices); - Ref _ibuff = gfx.IndexBuffer(indices); - + + Ref> _mesh = new Cube(0, 0, 0, 10, 20, 30); + unsigned int _rand_color = rand() * 1256; - - while (!IsStopped()) - { + + while (!IsStopped()) { if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { break; } - + gfx.Begin(_rand_color); - + PSCBuffer psCBuffer; - + DXMatrixIdentity(psCBuffer.world); DXMatrixIdentity(psCBuffer.view); - DXMatrixIdentity(psCBuffer.proj); - DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI/6, 1.5f, 0.1f, 100.0f); - DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -5), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); - - DXMatrix rotate; - static float x = 0; x += 0.1f; - DXMatrixRotationZ(rotate, x); - - DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate); - - + DXMatrixIdentity(psCBuffer.proj); + DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI / 6, 1.5f, 0.1f, 1000.0f); + DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -125), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); + + DXMatrix rotate_x; + static float x = 0; + x += 0.03f; + DXMatrixRotationX(rotate_x, x); + + DXMatrix rotate_y; + static float y = 0; + y += 0.01f; + DXMatrixRotationY(rotate_y, y); + + DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_x); + DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_y); + _shader_v.Ptr().SetCBuffer(psCBuffer); gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); - gfx.Render(_vbuff.Ptr(), _ibuff.Ptr()); - + + gfx.Render(_mesh.Ptr()); + gfx.End(); + + // break; } gfx.Stop(); return (INIT_SUCCEEDED); } + +#else + +int OnInit() { + // Nothing to test in non-MT5 environment. + return (INIT_SUCCEEDED); +} + +#endif \ No newline at end of file From bd3926d5207222d110ca372d5151e95f82f9c419 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 29 Apr 2021 21:43:12 +0200 Subject: [PATCH 06/97] WIP. Added lighting and camera setting. --- 3D/Chart3D.h | 52 ++++++++++++++++++++ 3D/Cube.h | 2 +- 3D/Device.h | 70 +++++++++++++++++++++++++-- 3D/Devices/MTDX/MTDXDevice.h | 2 +- 3D/Devices/MTDX/MTDXShader.h | 44 ++++++++++++++++- 3D/Face.h | 68 ++++++++++++++------------ 3D/Frontends/MT5Frontend.h | 5 +- 3D/Mesh.h | 72 +++++++++++++++++++--------- 3D/Shader.h | 11 +++++ 3D/Shaders/chart3d.ps.hlsl | 0 3D/Shaders/chart3d.vs.hlsl | 0 3D/TSR.h | 61 ++++++++++++++++++++++++ Util.h | 10 ++++ tests/3D/Shaders/pixel.hlsl | 9 ++-- tests/3D/Shaders/vertex.hlsl | 24 ++++++---- tests/3DTest.mq5 | 92 ++++++++++++++++++------------------ 16 files changed, 401 insertions(+), 121 deletions(-) create mode 100644 3D/Chart3D.h create mode 100644 3D/Shaders/chart3d.ps.hlsl create mode 100644 3D/Shaders/chart3d.vs.hlsl create mode 100644 3D/TSR.h diff --git a/3D/Chart3D.h b/3D/Chart3D.h new file mode 100644 index 000000000..bf093884e --- /dev/null +++ b/3D/Chart3D.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * 3D Chart. + */ + +#include "../Refs.mqh" +#include "Cube.h" +#include "Device.h" + +// Resources. +#resource "Shaders/chart3d.ps.hlsl" as string Chart3DShaderSourcePS; +#resource "Shaders/chart3d.vs.hlsl" as string Chart3DShaderSourceVS; + +class Chart3D : public Dynamic { + // Reference to graphics device. + WeakRef device; + + public: + /** + * Constructor. + */ + VertexBuffer(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } + + virtual void Select() = NULL; +}; \ No newline at end of file diff --git a/3D/Cube.h b/3D/Cube.h index b11194300..e9ea4d095 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -34,7 +34,7 @@ template class Cube : public Mesh { public: - Cube(float x = 0.0f, float y = 0.0f, float z = 0.0f, float size_x = 1.0f, float size_y = 1.0f, float size_z = 1.0f) { + Cube(float size_x, float size_y, float size_z, float x = 0.0f, float y = 0.0f, float z = 0.0f) { float half_x = size_x / 2; float half_y = size_y / 2; float half_z = size_z / 2; diff --git a/3D/Device.h b/3D/Device.h index e9b259e0a..6d0777244 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -26,6 +26,7 @@ */ #include "../Refs.mqh" +#include "../Util.h" #include "Frontend.h" #include "IndexBuffer.h" #include "Math.h" @@ -42,6 +43,11 @@ class Device : public Dynamic { protected: int context; Ref frontend; + DXMatrix mtx_stack[]; + DXMatrix mtx_world; + DXMatrix mtx_view; + DXMatrix mtx_projection; + DXVector3 lightdir; public: /** @@ -49,16 +55,29 @@ class Device : public Dynamic { */ bool Start(Frontend* _frontend) { frontend = _frontend; + DXMatrixIdentity(mtx_world); + DXMatrixIdentity(mtx_view); + DXMatrixIdentity(mtx_projection); + TSR _identity; + PushTransform(_identity); + lightdir = DXVector3(-0.2f, 0.2f, 1.0f); return Init(_frontend); } + void PushTransform(const TSR& tsr) { + mtx_world = tsr.ToMatrix(); + Util::ArrayPush(mtx_stack, mtx_world); + } + + void PopTransform() { mtx_world = Util::ArrayPop(mtx_stack); } + /** * Begins render loop. */ Device* Begin(unsigned int clear_color = 0) { frontend.Ptr().RenderBegin(context); - ClearDepth(); Clear(clear_color); + ClearDepth(); RenderBegin(); return &this; } @@ -142,17 +161,30 @@ class Device : public Dynamic { /** * Renders vertex buffer with optional point indices. */ - virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { RenderBuffers(_vertices, _indices); } + + /** + * Renders vertex buffer with optional point indices. + */ + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; /** * Renders given mesh. */ template - void Render(Mesh* _mesh) { + void Render(Mesh* _mesh, Shader* _vs = NULL, Shader* _ps = NULL) { Print("Rendering mesh"); VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); + if (_vs != NULL) { + SetShader(_vs); + } + if (_ps != NULL) { + SetShader(_ps); + } + // Setting MVP matrices. + Render(_vertices, _indices); } @@ -169,6 +201,38 @@ class Device : public Dynamic { _shader2.Select(); } + /** + * Returns front-end's viewport width. + */ + int Width() { return frontend.Ptr().Width(); } + + /** + * Returns front-end's viewport height. + */ + int Height() { return frontend.Ptr().Height(); } + + void SetCameraOrtho3D() { DXMatrixOrthoRH(mtx_view, Width(), Height(), -10000, 10000); } + + DXMatrix GetWorldMatrix() { return mtx_world; } + + void SetWorldMatrix(DXMatrix& _matrix) { mtx_world = _matrix; } + + DXMatrix GetViewMatrix() { return mtx_view; } + + void SetViewMatrix(DXMatrix& _matrix) { mtx_view = _matrix; } + + DXMatrix GetProjectionMatrix() { return mtx_projection; } + + void SetProjectionMatrix(DXMatrix& _matrix) { mtx_projection = _matrix; } + + DXVector3 GetLightDirection() { return lightdir; } + + void SetLightDirection(float x, float y, float z) { + lightdir.x = x; + lightdir.y = y; + lightdir.z = z; + } + protected: /** * Initializes graphics device. diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 5794160c2..96eddc266 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -126,7 +126,7 @@ class MTDXDevice : public Device { /** * */ - virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _vertices.Select(); if (_indices == NULL) { diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index 1fcf90a68..eacbfc484 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -31,7 +31,12 @@ class MTDXShader : public Shader { // DX context handle. int handle; - // DX C-Buffer handle. + // DX MVP's C-Buffer handle (register b0). + int cbuffer_mvp_handle; + + MVPBuffer mvp_buffer; + + // DX C-Buffer handle. (register b1). int cbuffer_handle; public: @@ -40,6 +45,15 @@ class MTDXShader : public Shader { */ MTDXShader(Device* _device) : Shader(_device) {} + /** + * Destructor. + */ + ~MTDXShader() { + DXRelease(cbuffer_handle); + DXRelease(cbuffer_mvp_handle); + DXRelease(handle); + } + /** * Creates a shader. */ @@ -53,6 +67,10 @@ class MTDXShader : public Shader { cbuffer_handle = 0; + // Creating MVP buffer. + cbuffer_mvp_handle = DXInputCreate(GetDevice().Context(), sizeof(MVPBuffer)); + Print("DXInputCreate (mvp): LastError: ", GetLastError()); + return true; } @@ -135,5 +153,27 @@ class MTDXShader : public Shader { /** * Selectes shader to be used by graphics device for rendering. */ - virtual void Select() { DXShaderSet(GetDevice().Context(), handle); } + virtual void Select() { + // Setting MVP transform. + mvp_buffer.world = GetDevice().GetWorldMatrix(); + mvp_buffer.view = GetDevice().GetViewMatrix(); + mvp_buffer.projection = GetDevice().GetProjectionMatrix(); + mvp_buffer.lightdir = GetDevice().GetLightDirection(); + + if (cbuffer_handle == 0) { + int _input_handles[1]; + _input_handles[0] = cbuffer_mvp_handle; + DXShaderInputsSet(handle, _input_handles); + } else { + int _input_handles[2]; + _input_handles[0] = cbuffer_mvp_handle; + _input_handles[1] = cbuffer_handle; + DXShaderInputsSet(handle, _input_handles); + } + + Print("DXShaderInputsSet: LastError: ", GetLastError()); + + DXInputSet(cbuffer_mvp_handle, mvp_buffer); + DXShaderSet(GetDevice().Context(), handle); + } }; \ No newline at end of file diff --git a/3D/Face.h b/3D/Face.h index c8a8ee9c9..7f7ad38af 100644 --- a/3D/Face.h +++ b/3D/Face.h @@ -44,30 +44,20 @@ struct Face { */ Face() { flags = FACE_FLAGS_NONE; } - /** - * Copy constructor. - */ - Face(const Face& r) { - flags = r.flags; - for (int p = 0; p < 4; ++p) { - points[p] = r.points[p]; - } - } - /** * Constructor. */ Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) { flags = FACE_FLAGS_TRIANGLE; - points[0].Position[0] = x1; - points[0].Position[1] = y1; - points[0].Position[2] = z1; - points[1].Position[0] = x2; - points[1].Position[1] = y2; - points[1].Position[2] = z2; - points[2].Position[0] = x3; - points[2].Position[1] = y3; - points[2].Position[2] = z3; + points[0].Position.x = x1; + points[0].Position.y = y1; + points[0].Position.z = z1; + points[1].Position.x = x2; + points[1].Position.y = y2; + points[1].Position.z = z2; + points[2].Position.x = x3; + points[2].Position.y = y3; + points[2].Position.z = z3; } /** @@ -76,17 +66,33 @@ struct Face { Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4) { flags = FACE_FLAGS_QUAD; - points[0].Position[0] = x1; - points[0].Position[1] = y1; - points[0].Position[2] = z1; - points[1].Position[0] = x2; - points[1].Position[1] = y2; - points[1].Position[2] = z2; - points[2].Position[0] = x3; - points[2].Position[1] = y3; - points[2].Position[2] = z3; - points[3].Position[0] = x4; - points[3].Position[1] = y4; - points[3].Position[2] = z4; + points[0].Position.x = x1; + points[0].Position.y = y1; + points[0].Position.z = z1; + points[1].Position.x = x2; + points[1].Position.y = y2; + points[1].Position.z = z2; + points[2].Position.x = x3; + points[2].Position.y = y3; + points[2].Position.z = z3; + points[3].Position.x = x4; + points[3].Position.y = y4; + points[3].Position.z = z4; + } + + void UpdateNormal() { + DXVector3 _normal, _v1, _v2; + + DXVec3Subtract(_v1, points[1].Position, points[0].Position); + DXVec3Subtract(_v2, points[2].Position, points[0].Position); + + DXVec3Cross(_normal, _v1, _v2); + DXVec3Normalize(_normal, _normal); + + // Print("cross = ", _normal.x, ", ", _normal.y, ", ", _normal.z); + + for (int i = 0; i < 4; ++i) { + points[i].Normal = _normal; + } } }; \ No newline at end of file diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 3d75592ec..357b4266a 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -75,6 +75,7 @@ class MT5Frontend : public Frontend { ResourceFree(resname); ObjectDelete(0, objname); ChartSetInteger(0, CHART_SHOW, true); + ChartRedraw(); return true; } @@ -88,7 +89,7 @@ class MT5Frontend : public Frontend { ArrayResize(image, Width() * Height()); Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); - ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); Print("ResourceCreate: LastError: ", GetLastError()); last_width = Width(); @@ -120,7 +121,7 @@ class MT5Frontend : public Frontend { Print("MT5Frontend: DXContextGetColors()"); DXContextGetColors(context, image); Print("DXContextGetColors: LastError: ", GetLastError()); - ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); Print("ResourceCreate: LastError: ", GetLastError()); ChartRedraw(); Sleep(5); diff --git a/3D/Mesh.h b/3D/Mesh.h index 2d28ddaf9..d09d6ab1a 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -31,6 +31,7 @@ #include "Face.h" #include "IndexBuffer.h" #include "Math.h" +#include "TSR.h" #include "VertexBuffer.h" class Device; @@ -47,11 +48,11 @@ struct PointEntry { PointEntry(const T& _point) { point = _point; - key = MakeKey(_point.Position[0], _point.Position[1], _point.Position[2]); + key = MakeKey(_point.Position.x, _point.Position.y, _point.Position.z); } bool operator==(const PointEntry& _r) { - return key == MakeKey(_r.point.Position[0], _r.point.Position[1], _r.point.Position[2]); + return key == MakeKey(_r.point.Position.x, _r.point.Position.y, _r.point.Position.z); } static long MakeKey(float x, float y, float z) { @@ -60,22 +61,30 @@ struct PointEntry { } }; +// Mesh points type. +enum ENUM_MESH_TYPE { MESH_TYPE_CONNECTED_POINTS, MESH_TYPE_SEPARATE_POINTS }; + template class Mesh : public Dynamic { Ref vbuff; Ref ibuff; Face faces[]; + TSR tsr; + ENUM_MESH_TYPE type; public: /** * Constructor. */ - Mesh() {} + Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) { type = _type; } /** * Adds a single 3 or 4-vertex face. */ - void AddFace(Face& face) { Util::ArrayPush(faces, face, 16); } + void AddFace(Face& face) { + face.UpdateNormal(); + Util::ArrayPush(faces, face, 16); + } /** * Returns vertex and index buffers for this mesh. @@ -83,6 +92,7 @@ class Mesh : public Dynamic { * @todo Buffers should be invalidated if mesh has changed. */ bool GetBuffers(Device* _device, VertexBuffer*& _vbuff, IndexBuffer*& _ibuff) { + Print("Getting buffers. Mesh type = ", EnumToString(type)); if (vbuff.IsSet() && ibuff.IsSet()) { _vbuff = vbuff.Ptr(); _ibuff = ibuff.Ptr(); @@ -100,12 +110,12 @@ class Mesh : public Dynamic { // Adding first triangle. for (k = 0; k < 3; ++k) { - PointEntry point1(_face.points[k]); - _face_indices[k] = _points.IndexOf(point1); + PointEntry _point1(_face.points[k]); + _face_indices[k] = type == MESH_TYPE_SEPARATE_POINTS ? -1 : _points.IndexOf(_point1); if (_face_indices[k] == -1) { // Point not yet added. - _points.Push(point1); + _points.Push(_point1); _face_indices[k] = (int)_points.Size() - 1; } @@ -114,18 +124,36 @@ class Mesh : public Dynamic { // Adding second triangle if needed. if ((_face.flags & FACE_FLAGS_QUAD) == FACE_FLAGS_QUAD) { - PointEntry point2(_face.points[3]); - _face_indices[3] = _points.IndexOf(point2); - - if (_face_indices[3] == -1) { - // Point not yet added. - _points.Push(point2); - _face_indices[3] = (int)_points.Size() - 1; + if (type == MESH_TYPE_CONNECTED_POINTS) { + PointEntry _point3(_face.points[3]); + _face_indices[3] = _points.IndexOf(_point3); + + if (_face_indices[3] == -1) { + // Point not yet added. + _points.Push(_point3); + _face_indices[3] = (int)_points.Size() - 1; + } + + Util::ArrayPush(_indices, _face_indices[0]); + Util::ArrayPush(_indices, _face_indices[2]); + Util::ArrayPush(_indices, _face_indices[3]); + } else { + int _i1 = ArraySize(_indices) + 0; + int _i2 = ArraySize(_indices) + 1; + int _i3 = ArraySize(_indices) + 2; + + Util::ArrayPush(_indices, _i1); + Util::ArrayPush(_indices, _i2); + Util::ArrayPush(_indices, _i3); + + PointEntry _point0(_face.points[0]); + PointEntry _point2(_face.points[2]); + PointEntry _point3(_face.points[3]); + + _points.Push(_point0); + _points.Push(_point2); + _points.Push(_point3); } - - Util::ArrayPush(_indices, _face_indices[0]); - Util::ArrayPush(_indices, _face_indices[2]); - Util::ArrayPush(_indices, _face_indices[3]); } } @@ -139,10 +167,10 @@ class Mesh : public Dynamic { for (i = 0; i < ArraySize(_vertices); ++i) { _s_vertices += "["; - _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position[0]) + ", " + - DoubleToString(_vertices[i].Position[1]) + "," + DoubleToString(_vertices[i].Position[2]) + " | "; - _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color[0]) + ", " + DoubleToString(_vertices[i].Color[1]) + - "," + DoubleToString(_vertices[i].Color[2]) + "," + DoubleToString(_vertices[i].Color[3]); + _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position.x) + ", " + + DoubleToString(_vertices[i].Position.y) + "," + DoubleToString(_vertices[i].Position.z) + " | "; + _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color.x) + ", " + DoubleToString(_vertices[i].Color.y) + + "," + DoubleToString(_vertices[i].Color.z) + "," + DoubleToString(_vertices[i].Color.w); _s_vertices += "]"; if (i != ArraySize(_vertices) - 1) { _s_vertices += ", "; diff --git a/3D/Shader.h b/3D/Shader.h index 1500a1430..1b3b09938 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -38,6 +38,17 @@ class MTDXShader; enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; +// Note that shader buffers's size must be multiple of 4! +struct MVPBuffer { + DXMatrix world; + DXMatrix view; + DXMatrix projection; + DXVector3 lightdir; + + private: + char _unused[4]; +}; + // Vertex layout used for Vertex Shaders. struct ShaderVertexLayout { string name; diff --git a/3D/Shaders/chart3d.ps.hlsl b/3D/Shaders/chart3d.ps.hlsl new file mode 100644 index 000000000..e69de29bb diff --git a/3D/Shaders/chart3d.vs.hlsl b/3D/Shaders/chart3d.vs.hlsl new file mode 100644 index 000000000..e69de29bb diff --git a/3D/TSR.h b/3D/TSR.h new file mode 100644 index 000000000..09247b830 --- /dev/null +++ b/3D/TSR.h @@ -0,0 +1,61 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Translations, scale and rotation matrices. + */ + +#include "Math.h" + +struct TSR { + DXVector3 translation; + DXVector3 scale; + DXVector3 rotation; + + TSR() { + translation.x = translation.y = translation.z = 0.0f; + scale.x = scale.y = scale.z = 1.0f; + rotation.x = rotation.y = rotation.z = 0.0f; + } + + DXMatrix ToMatrix() const { + DXMatrix _mtx_translation = {}; + DXMatrix _mtx_scale = {}; + DXMatrix _mtx_rotation_1 = {}; + DXMatrix _mtx_rotation_2 = {}; + DXMatrix _mtx_result = {}; + + DXMatrixTranslation(_mtx_translation, translation.x, translation.y, translation.z); + DXMatrixScaling(_mtx_scale, scale.x, scale.y, scale.z); + DXMatrixRotationYawPitchRoll(_mtx_rotation_1, rotation.x, 0, rotation.z); + DXMatrixRotationYawPitchRoll(_mtx_rotation_2, 0, rotation.y, 0); + + DXMatrixIdentity(_mtx_result); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_1); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_2); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_scale); + + return _mtx_result; + } +}; \ No newline at end of file diff --git a/Util.h b/Util.h index e562d1955..06676caf0 100644 --- a/Util.h +++ b/Util.h @@ -43,4 +43,14 @@ class Util { _array[ArraySize(_array) - 1] = _value; return ArraySize(_array) - 1; } + + /** + * Resizes native array and reserves space for further items by some fixed step. + */ + template + static T ArrayPop(T& _array[]) { + T _result = _array[ArraySize(_array) - 1]; + ::ArrayResize(_array, ArraySize(_array) - 1); + return _result; + } }; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index e4ddb278c..6cdb51f59 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,11 +1,14 @@ -struct PSInput +struct INPUT { float4 position : SV_POSITION; + float4 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; float4 color : COLOR; }; -float4 main(PSInput input) : SV_TARGET +float4 main(INPUT input) : SV_TARGET { - return input.color; + float4 ambient = {0.0, 0.2, 0.4, 1.0}; + return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); } //+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index 6a92c8b1b..ab4715043 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -1,32 +1,38 @@ -cbuffer CBuffer +cbuffer MVP : register(b0) { matrix world; matrix view; - matrix proj; + matrix projection; + float3 lightdir; }; -struct VSInput +struct INPUT { float4 position : POSITION; + float3 normal : NORMAL; float4 color : COLOR; }; -struct PSInput +struct OUTPUT { float4 position : SV_POSITION; + float3 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; float4 color : COLOR; }; -PSInput main(VSInput input) +OUTPUT main(INPUT input) { - PSInput output; + OUTPUT output; input.position.w = 1.0f; - output.position = mul(world, input.position); - output.position = mul(view, output.position); - output.position = mul(proj, output.position); + matrix mvp = mul(mul(projection, view), world); + output.position = mul(mvp, input.position); + + output.normal = normalize(mul(world, input.normal)); + output.lightdir = lightdir; output.color = input.color; return output; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 6211ca9ac..c3b3d43a5 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -30,6 +30,8 @@ #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; +//#define Print if (false) Print + // Includes. #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" @@ -42,83 +44,79 @@ // int OnStart() { return OnInit(); } struct Vertex { - float Position[3]; - float Color[4]; + DXVector3 Position; + DXVector3 Normal; + DXVector Color; Vertex() { - Color[0] = 1.0f / 65535 * rand(); - Color[1] = 1.0f / 65535 * rand(); - Color[2] = 1.0f / 65535 * rand(); - Color[3] = 1.0f; + Color.x = 1.0f; + Color.y = 1.0f; + Color.z = 1.0f; + Color.w = 1.0f; } }; const ShaderVertexLayout VertexLayout[] = { {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, - {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 3}, -}; + {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, + {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; -struct PSCBuffer { - DXMatrix world; - DXMatrix view; - DXMatrix proj; -}; +struct PSCBuffer : MVPBuffer {}; /** * Implements Oninit(). */ int OnInit() { Ref gfx_ptr = new MTDXDevice(); - Device* gfx = gfx_ptr.Ptr(); - gfx.Start(new MT5Frontend()); + // Making a scope to ensure graphics device will be destructed as last. + { + Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Device* gfx = gfx_ptr.Ptr(); - Ref> _mesh = new Cube(0, 0, 0, 10, 20, 30); + gfx.Start(new MT5Frontend()); - unsigned int _rand_color = rand() * 1256; + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); + Ref _shader_p = gfx.PixelShader(ShaderSourcePS); - while (!IsStopped()) { - if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { - break; - } + unsigned int _rand_color = rand() * 1256; - gfx.Begin(_rand_color); + gfx.SetCameraOrtho3D(); + gfx.SetLightDirection(0, 0, -1.0f); - PSCBuffer psCBuffer; + while (!IsStopped()) { + if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { + break; + } - DXMatrixIdentity(psCBuffer.world); - DXMatrixIdentity(psCBuffer.view); - DXMatrixIdentity(psCBuffer.proj); - DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI / 6, 1.5f, 0.1f, 1000.0f); - DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -125), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); + gfx.Begin(0x777255EE); - DXMatrix rotate_x; - static float x = 0; - x += 0.03f; - DXMatrixRotationX(rotate_x, x); + static float x = 0; + x += 0.04f; - DXMatrix rotate_y; - static float y = 0; - y += 0.01f; - DXMatrixRotationY(rotate_y, y); + TSR tsr; + tsr.rotation.x = x; - DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_x); - DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_y); + gfx.PushTransform(tsr); + gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.PopTransform(); - _shader_v.Ptr().SetCBuffer(psCBuffer); - gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); + tsr.translation.x = 50; + tsr.translation.y = -180; + tsr.rotation.z = 1.9f; - gfx.Render(_mesh.Ptr()); + gfx.PushTransform(tsr); + gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.PopTransform(); - gfx.End(); + gfx.End(); - // break; - } + // break; + } - gfx.Stop(); + gfx.Stop(); + } return (INIT_SUCCEEDED); } From 5c5075886155bcbbfcd3eec8c4b16f9d02e27520 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 7 May 2021 19:32:11 +0200 Subject: [PATCH 07/97] WIP. Battle with MetaEditor and Visualizer... --- 3D/Chart3D.h | 94 +++++++++++++++++-- 3D/Chart3DCandles.h | 52 ++++++++++ 3D/Chart3DType.h | 50 ++++++++++ 3D/Cube.h | 12 +++ 3D/Device.h | 10 +- 3D/Mesh.h | 38 +++++++- .../{chart3d.ps.hlsl => chart3d_ps.hlsl} | 0 .../{chart3d.vs.hlsl => chart3d_vs.hlsl} | 0 3D/Shaders/cube_ps.hlsl | 12 +++ 3D/Shaders/cube_vs.hlsl | 35 +++++++ 3D/Vertex.h | 29 ++++-- tests/3DTest.mq5 | 45 ++++----- 12 files changed, 328 insertions(+), 49 deletions(-) create mode 100644 3D/Chart3DCandles.h create mode 100644 3D/Chart3DType.h rename 3D/Shaders/{chart3d.ps.hlsl => chart3d_ps.hlsl} (100%) rename 3D/Shaders/{chart3d.vs.hlsl => chart3d_vs.hlsl} (100%) create mode 100644 3D/Shaders/cube_ps.hlsl create mode 100644 3D/Shaders/cube_vs.hlsl diff --git a/3D/Chart3D.h b/3D/Chart3D.h index bf093884e..4cb721ed7 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -25,28 +25,106 @@ * 3D Chart. */ +#include "../Bar.struct.h" #include "../Refs.mqh" +#include "../SerializerConverter.mqh" +#include "../SerializerJson.mqh" +#include "Chart3DCandles.h" +#include "Chart3DType.h" #include "Cube.h" #include "Device.h" // Resources. -#resource "Shaders/chart3d.ps.hlsl" as string Chart3DShaderSourcePS; -#resource "Shaders/chart3d.vs.hlsl" as string Chart3DShaderSourceVS; +#resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; +#resource "Shaders/chart3d_ps.hlsl" as string Chart3DShaderSourcePS; +typedef BarOHLC (*Chart3DPriceFetcher)(ENUM_TIMEFRAMES, int); + +// Type of the currently rendered 3d chart. +enum ENUM_CHART3D_TYPE { + CHART3D_TYPE_BARS, + CHART3D_TYPE_CANDLES, + CHART3D_TYPE_LINES, +}; + +/** + * 3D chart renderer. + */ class Chart3D : public Dynamic { - // Reference to graphics device. - WeakRef device; + // Camera offset. Z component indicates number of bars per screen's width. + DXVector3 offset; + + // Current chart type. + ENUM_CHART3D_TYPE type; + + // References to chart type renderers. + Ref renderers[3]; + + // OHLC prices fetcher callback. + Chart3DPriceFetcher price_fetcher; + + // Whether graphics were initialized. + bool initialized; + + // Shaders. + Ref shader_vs; + Ref shader_ps; public: /** * Constructor. */ - VertexBuffer(Device* _device) { device = _device; } + Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) { + price_fetcher = _price_fetcher; + type = _type; + offset.x = offset.y = 0.0f; + offset.z = 25.0f; + initialized = false; + } + + Shader* GetShaderVS() { return shader_vs.Ptr(); } + + Shader* GetShaderPS() { return shader_ps.Ptr(); } + + Chart3DType* GetRenderer(Device* _device) { + if (!initialized) { + // shader_vs = _device.VertexShader(Chart3DShaderSourceVS, Vertex::Layout); + // shader_ps = _device.PixelShader(Chart3DShaderSourcePS); + initialized = true; + } + + if (!renderers[type].IsSet()) { + switch (type) { + case CHART3D_TYPE_BARS: + // renderers[type] = new Chart3DBars(_device); + break; + case CHART3D_TYPE_CANDLES: + renderers[type] = new Chart3DCandles(&this, _device); + break; + case CHART3D_TYPE_LINES: + // renderers[type] = new Chart3DLines(_device); + break; + default: + Alert("Internal error: Wrong type for Chart3D in Chart3D::GetRenderer()!"); + DebugBreak(); + return NULL; + } + } + + return renderers[type].Ptr(); + } + + BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } /** - * Returns base graphics device. + * Renders chart. */ - Device* GetDevice() { return device.Ptr(); } + void Render(Device* _device) { + Chart3DType* _type_renderer = GetRenderer(_device); + + BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); + Print(SerializerConverter::FromObject(_ohlc).ToString()); - virtual void Select() = NULL; + _type_renderer.Render(_device); + } }; \ No newline at end of file diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h new file mode 100644 index 000000000..48e0ef336 --- /dev/null +++ b/3D/Chart3DCandles.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * 3D chart candles renderer. + */ + +#include "Chart3DType.h" +#include "Device.h" +#include "Vertex.h" + +class Chart; + +/** + * 3D chart candles renderer. + */ +class Chart3DCandles : public Chart3DType { + Ref> cube; + + public: + /** + * Constructor. + */ + Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { + cube = new Cube(100.0f, 100.0f, 100.0f); + } + + /** + * Renders chart. + */ + virtual void Render(Device* _device) { _device.Render(cube.Ptr()); } +}; \ No newline at end of file diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h new file mode 100644 index 000000000..6ff1ad808 --- /dev/null +++ b/3D/Chart3DType.h @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * 3D chart type renderer. + */ + +#include "../Refs.mqh" +#include "Device.h" + +class Chart3D; +class Device; + +/** + * 3D chart type renderer. + */ +class Chart3DType : public Dynamic { + public: + Device* device; + + /** + * Constructor. + */ + Chart3DType(Chart3D* _chart3d, Device* _device) : device(_device) {} + + /** + * Renders chart. + */ + virtual void Render(Device* _device) {} +}; \ No newline at end of file diff --git a/3D/Cube.h b/3D/Cube.h index e9ea4d095..efc3d7478 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -28,6 +28,10 @@ #include "Face.h" #include "Mesh.h" +// Resources. +#resource "Shaders/cube_ps.hlsl" as string ShaderCubeSourcePS; +#resource "Shaders/cube_vs.hlsl" as string ShaderCubeSourceVS; + /** * Cube mesh. */ @@ -64,4 +68,12 @@ class Cube : public Mesh { AddFace(f5); AddFace(f6); } + + /** + * Initializes graphics device-related things. + */ + virtual void Initialize(Device* _device) { + SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); + SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); + } }; \ No newline at end of file diff --git a/3D/Device.h b/3D/Device.h index 6d0777244..513b810dd 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -177,13 +177,9 @@ class Device : public Dynamic { VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); - if (_vs != NULL) { - SetShader(_vs); - } - if (_ps != NULL) { - SetShader(_ps); - } - // Setting MVP matrices. + + SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS()); + SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS()); Render(_vertices, _indices); } diff --git a/3D/Mesh.h b/3D/Mesh.h index d09d6ab1a..681a63851 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -68,15 +68,26 @@ template class Mesh : public Dynamic { Ref vbuff; Ref ibuff; + Ref shader_ps; + Ref shader_vs; Face faces[]; TSR tsr; ENUM_MESH_TYPE type; + bool initialized; public: /** * Constructor. */ - Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) { type = _type; } + Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) { + type = _type; + initialized = false; + } + + /** + * Initializes graphics device-related things. + */ + virtual void Initialize(Device* _device) {} /** * Adds a single 3 or 4-vertex face. @@ -86,12 +97,37 @@ class Mesh : public Dynamic { Util::ArrayPush(faces, face, 16); } + /** + * Returns vertex shader for mesh rendering. + */ + Shader* GetShaderVS() { return shader_vs.Ptr(); } + + /** + * Sets pixel shader for mesh rendering. + */ + void SetShaderVS(Shader* _shader_vs) { shader_vs = _shader_vs; } + + /** + * Returns pixel shader for mesh rendering. + */ + Shader* GetShaderPS() { return shader_ps.Ptr(); } + + /** + * Sets pixel shader for mesh rendering. + */ + void SetShaderPS(Shader* _shader_ps) { shader_ps = _shader_ps; } + /** * Returns vertex and index buffers for this mesh. * * @todo Buffers should be invalidated if mesh has changed. */ bool GetBuffers(Device* _device, VertexBuffer*& _vbuff, IndexBuffer*& _ibuff) { + if (!initialized) { + Initialize(_device); + initialized = true; + } + Print("Getting buffers. Mesh type = ", EnumToString(type)); if (vbuff.IsSet() && ibuff.IsSet()) { _vbuff = vbuff.Ptr(); diff --git a/3D/Shaders/chart3d.ps.hlsl b/3D/Shaders/chart3d_ps.hlsl similarity index 100% rename from 3D/Shaders/chart3d.ps.hlsl rename to 3D/Shaders/chart3d_ps.hlsl diff --git a/3D/Shaders/chart3d.vs.hlsl b/3D/Shaders/chart3d_vs.hlsl similarity index 100% rename from 3D/Shaders/chart3d.vs.hlsl rename to 3D/Shaders/chart3d_vs.hlsl diff --git a/3D/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl new file mode 100644 index 000000000..b6710ff2d --- /dev/null +++ b/3D/Shaders/cube_ps.hlsl @@ -0,0 +1,12 @@ +struct INPUT { + float4 position : SV_POSITION; + float4 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; + float4 color : COLOR; +}; + +float4 main(INPUT input) : SV_TARGET { + float4 ambient = {0.0, 0.2, 0.4, 1.0}; + return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); +} +//+------------------------------------------------------------------+ diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl new file mode 100644 index 000000000..a1ea75989 --- /dev/null +++ b/3D/Shaders/cube_vs.hlsl @@ -0,0 +1,35 @@ +cbuffer MVP : register(b0) { + matrix world; + matrix view; + matrix projection; + float3 lightdir; +}; + +struct INPUT { + float4 position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR; +}; + +struct OUTPUT { + float4 position : SV_POSITION; + float3 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; + float4 color : COLOR; +}; + +OUTPUT main(INPUT input) { + OUTPUT output; + + input.position.w = 1.0f; + + matrix mvp = mul(mul(projection, view), world); + + output.position = mul(mvp, input.position); + + output.normal = normalize(mul(world, input.normal)); + output.lightdir = lightdir; + output.color = input.color; + + return output; +} \ No newline at end of file diff --git a/3D/Vertex.h b/3D/Vertex.h index 6561fad32..83ccfe50f 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -1,11 +1,24 @@ #include "../Refs.mqh" +/** + * Generic vertex to be used by meshes. + */ struct Vertex { - struct Position { - float x, y, z; - } position; - - struct Color { - float r, g, b, a; - } color; -}; \ No newline at end of file + DXVector3 Position; + DXVector3 Normal; + DXVector Color; + + Vertex() { + Color.x = 1.0f; + Color.y = 1.0f; + Color.z = 1.0f; + Color.w = 1.0f; + } + + static const ShaderVertexLayout Layout[3]; +}; + +const ShaderVertexLayout Vertex::Layout[3] = { + {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, + {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, + {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index c3b3d43a5..a58290c6f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -33,53 +33,46 @@ //#define Print if (false) Print // Includes. +#include "../3D/Chart3D.h" #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" #include "../3D/Devices/MTDX/MTDXIndexBuffer.h" #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../3D/Frontends/MT5Frontend.h" +#include "../Chart.mqh" +#include "../Serializer.mqh" #include "../Test.mqh" // int OnStart() { return OnInit(); } -struct Vertex { - DXVector3 Position; - DXVector3 Normal; - DXVector Color; +BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { return Chart::GetOHLC(_tf, _shift); } - Vertex() { - Color.x = 1.0f; - Color.y = 1.0f; - Color.z = 1.0f; - Color.w = 1.0f; - } -}; - -const ShaderVertexLayout VertexLayout[] = { - {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, - {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, - {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; +int OnInit() { return OnStart(); } struct PSCBuffer : MVPBuffer {}; /** - * Implements Oninit(). + * Implements OnStart(). */ -int OnInit() { +int OnStart() { Ref gfx_ptr = new MTDXDevice(); // Making a scope to ensure graphics device will be destructed as last. { - Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); - Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); + _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); + _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); + + Ref _chart = new Chart3D(ChartPriceFeeder, CHART3D_TYPE_CANDLES); + unsigned int _rand_color = rand() * 1256; gfx.SetCameraOrtho3D(); @@ -99,7 +92,7 @@ int OnInit() { tsr.rotation.x = x; gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.Render(_mesh.Ptr()); gfx.PopTransform(); tsr.translation.x = 50; @@ -107,17 +100,19 @@ int OnInit() { tsr.rotation.z = 1.9f; gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.Render(_mesh.Ptr()); gfx.PopTransform(); + _chart.Ptr().Render(gfx); + gfx.End(); // break; } - - gfx.Stop(); } + gfx_ptr.Ptr().Stop(); + return (INIT_SUCCEEDED); } From 479ff9ee475b256332410bdce6d9b0e61895809f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 12 May 2021 20:33:30 +0200 Subject: [PATCH 08/97] WIP. First try to render bars. --- 3D/Chart3D.h | 19 ++ 3D/Chart3DCandles.h | 27 ++- 3D/Chart3DType.h | 6 +- 3D/Cube.h | 3 +- 3D/Device.h | 36 +++- 3D/Devices/MTDX/MTDXDevice.h | 14 ++ 3D/Devices/MTDX/MTDXIndexBuffer.h | 4 + 3D/Devices/MTDX/MTDXShader.h | 28 ++- 3D/Devices/MTDX/MTDXVertexBuffer.h | 6 + 3D/Face.h | 2 - 3D/Frontends/MT5Frontend.h | 26 ++- 3D/Math.h | 278 +++++++++++++++-------------- 3D/Mesh.h | 24 ++- 3D/Shader.h | 12 +- 3D/Shaders/cube_ps.hlsl | 3 +- 3D/Shaders/cube_vs.hlsl | 12 +- 3D/TSR.h | 3 +- 3D/Vertex.h | 10 +- Refs.struct.h | 4 + tests/3D/Shaders/pixel.hlsl | 10 +- tests/3DTest.mq5 | 27 +-- 21 files changed, 355 insertions(+), 199 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 4cb721ed7..e8568a482 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -116,6 +116,22 @@ class Chart3D : public Dynamic { BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } + int GetBarsVisibleShiftStart() { return 20; } + + int GetBarsVisibleShiftEnd() { return 0; } + + int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; } + + float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.1f / 2.0f + 1.1f * _shift; } + + float GetPriceScale(float price) { + float _scale_y = 1.0f; + float _price_min = 1.194f; + float _price_max = 1.20f; + // Print(price); + return _scale_y / (_price_max - _price_min) * (price - _price_min); + } + /** * Renders chart. */ @@ -123,7 +139,10 @@ class Chart3D : public Dynamic { Chart3DType* _type_renderer = GetRenderer(_device); BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); + +#ifdef __debug__ Print(SerializerConverter::FromObject(_ohlc).ToString()); +#endif _type_renderer.Render(_device); } diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 48e0ef336..baf4b45f6 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -26,27 +26,46 @@ */ #include "Chart3DType.h" +#include "Cube.h" #include "Device.h" #include "Vertex.h" -class Chart; +class Chart3D; /** * 3D chart candles renderer. */ class Chart3DCandles : public Chart3DType { - Ref> cube; + Ref> cube1; + Ref> cube2; public: /** * Constructor. */ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { - cube = new Cube(100.0f, 100.0f, 100.0f); + cube1 = new Cube(1.0f, 1.0f, 1.0f); + cube2 = new Cube(0.15f, 0.15f, 0.15f); } /** * Renders chart. */ - virtual void Render(Device* _device) { _device.Render(cube.Ptr()); } + virtual void Render(Device* _device) { + TSR _tsr; + + for (int _shift = chart3d.GetBarsVisibleShiftStart(); _shift != chart3d.GetBarsVisibleShiftEnd(); --_shift) { + BarOHLC _ohlc = chart3d.GetPrice(PERIOD_CURRENT, _shift); + + cube1.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); + cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.open); + cube1.Ptr().GetMaterial().SetColor(0xFF0000); + _device.Render(cube1.Ptr()); + + cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); + cube2.Ptr().GetTSR().scale.y = 10.0f; + cube2.Ptr().GetMaterial().SetColor(0xFF0000); + _device.Render(cube2.Ptr()); + } + } }; \ No newline at end of file diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h index 6ff1ad808..d96de2463 100644 --- a/3D/Chart3DType.h +++ b/3D/Chart3DType.h @@ -35,13 +35,15 @@ class Device; * 3D chart type renderer. */ class Chart3DType : public Dynamic { - public: + protected: + Chart3D* chart3d; Device* device; + public: /** * Constructor. */ - Chart3DType(Chart3D* _chart3d, Device* _device) : device(_device) {} + Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {} /** * Renders chart. diff --git a/3D/Cube.h b/3D/Cube.h index efc3d7478..5d0c69d45 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -38,7 +38,8 @@ template class Cube : public Mesh { public: - Cube(float size_x, float size_y, float size_z, float x = 0.0f, float y = 0.0f, float z = 0.0f) { + Cube(float size_x, float size_y, float size_z, float x = 0.0f, float y = 0.0f, float z = 0.0f) + : Mesh(MESH_TYPE_SEPARATE_POINTS) { float half_x = size_x / 2; float half_y = size_y / 2; float half_z = size_z / 2; diff --git a/3D/Device.h b/3D/Device.h index 513b810dd..5fd811132 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -29,6 +29,7 @@ #include "../Util.h" #include "Frontend.h" #include "IndexBuffer.h" +#include "Material.h" #include "Math.h" #include "Mesh.h" #include "Shader.h" @@ -48,6 +49,7 @@ class Device : public Dynamic { DXMatrix mtx_view; DXMatrix mtx_projection; DXVector3 lightdir; + Material material; public: /** @@ -65,8 +67,8 @@ class Device : public Dynamic { } void PushTransform(const TSR& tsr) { - mtx_world = tsr.ToMatrix(); Util::ArrayPush(mtx_stack, mtx_world); + DXMatrixMultiply(mtx_world, tsr.ToMatrix(), mtx_world); } void PopTransform() { mtx_world = Util::ArrayPop(mtx_stack); } @@ -115,6 +117,16 @@ class Device : public Dynamic { return &this; } + /** + * Returns current material. + */ + Material GetMaterial() { return material; } + + /** + * Assigns material for later rendering. + */ + void SetMaterial(Material& _material) { material = _material; } + /** * Returns graphics device context as integer. */ @@ -139,8 +151,10 @@ class Device : public Dynamic { VertexBuffer* _buff = VertexBuffer(); // Unfortunately we can't make this method virtual. if (dynamic_cast(_buff) != NULL) { - // MT5's DirectX. +// MT5's DirectX. +#ifdef __debug__ Print("Filling vertex buffer via MTDXVertexBuffer"); +#endif ((MTDXVertexBuffer*)_buff).Fill(data); } else { Alert("Unsupported vertex buffer device target"); @@ -173,15 +187,22 @@ class Device : public Dynamic { */ template void Render(Mesh* _mesh, Shader* _vs = NULL, Shader* _ps = NULL) { +#ifdef __debug__ Print("Rendering mesh"); +#endif VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); + PushTransform(_mesh.GetTSR()); + + SetMaterial(_mesh.GetMaterial()); SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS()); SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS()); Render(_vertices, _indices); + + PopTransform(); } /** @@ -207,7 +228,16 @@ class Device : public Dynamic { */ int Height() { return frontend.Ptr().Height(); } - void SetCameraOrtho3D() { DXMatrixOrthoRH(mtx_view, Width(), Height(), -10000, 10000); } + void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { + DXMatrixOrthoLH(mtx_view, 1.0f, 1.0f / Width() * Height(), -10000, 10000); + mtx_view.m[3][3] = _pos_z; + DXMatrix _translate; + DXMatrix _scale; + DXMatrixTranslation(_translate, _pos_x, _pos_y, 0.0f); + DXMatrixTranslation(_scale, 1.0f / _pos_z, 1.0f / _pos_z, 0.0f); + // DXMatrixMultiply(mtx_view, _translate, mtx_view); + // DXMatrixMultiply(mtx_view, mtx_view, _scale); + } DXMatrix GetWorldMatrix() { return mtx_world; } diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 96eddc266..6200f1b36 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -33,10 +33,14 @@ class MTDXDevice : public Device { * Initializes graphics device. */ bool Init(Frontend* _frontend) { +#ifdef __debug__ Print("MTDXDevice: DXContextCreate: width = ", _frontend.Width(), ", height = ", _frontend.Height()); +#endif context = DXContextCreate(_frontend.Width(), _frontend.Height()); +#ifdef __debug__ Print("LastError: ", GetLastError()); Print("MTDXDevice: context = ", context); +#endif _frontend.Init(); return true; } @@ -78,10 +82,14 @@ class MTDXDevice : public Device { _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); +#ifdef __debug__ Print("DXContextClearColors: LastError: ", GetLastError()); +#endif } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); +#ifdef __debug__ Print("DXContextClearDepth: LastError: ", GetLastError()); +#endif } } @@ -131,13 +139,19 @@ class MTDXDevice : public Device { _vertices.Select(); if (_indices == NULL) { if (!DXDraw(context)) { +#ifdef __debug__ Print("Can't draw!"); +#endif } +#ifdef __debug__ Print("DXDraw: LastError: ", GetLastError()); +#endif } else { _indices.Select(); DXDrawIndexed(context); +#ifdef __debug__ Print("DXDrawIndexed: LastError: ", GetLastError()); +#endif } } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index ae6d6ff3c..60b33124f 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -58,8 +58,12 @@ class MTDXIndexBuffer : public IndexBuffer { * Activates index buffer for rendering. */ virtual void Select() { +#ifdef __debug__ Print("Selecting indices ", handle); +#endif DXBufferSet(GetDevice().Context(), handle); +#ifdef __debug__ Print("Select: LastError: ", GetLastError()); +#endif } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index eacbfc484..6a5b951c4 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -63,13 +63,17 @@ class MTDXShader : public Shader { handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, error_text); +#ifdef __debug__ Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); +#endif cbuffer_handle = 0; // Creating MVP buffer. cbuffer_mvp_handle = DXInputCreate(GetDevice().Context(), sizeof(MVPBuffer)); +#ifdef __debug__ Print("DXInputCreate (mvp): LastError: ", GetLastError()); +#endif return true; } @@ -83,7 +87,9 @@ class MTDXShader : public Shader { DXVertexLayout _target_layout[]; ArrayResize(_target_layout, ArraySize(_layout)); +#ifdef __debug__ Print("ArrayResize: LastError: ", GetLastError()); +#endif int i; @@ -93,16 +99,20 @@ class MTDXShader : public Shader { _target_layout[i].format = ParseFormat(_layout[i]); } +#ifdef __debug__ for (i = 0; i < ArraySize(_target_layout); ++i) { Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", EnumToString(_target_layout[i].format)); } Print("before DXShaderSetLayout: LastError: ", GetLastError()); +#endif DXShaderSetLayout(handle, _target_layout); +#ifdef __debug__ Print("DXShaderSetLayout: LastError: ", GetLastError()); +#endif ResetLastError(); } @@ -137,28 +147,36 @@ class MTDXShader : public Shader { void SetCBuffer(const X& data) { if (cbuffer_handle == 0) { cbuffer_handle = DXInputCreate(GetDevice().Context(), sizeof(X)); +#ifdef __debug__ Print("DXInputCreate: LastError: ", GetLastError()); +#endif int _input_handles[1]; _input_handles[0] = cbuffer_handle; DXShaderInputsSet(handle, _input_handles); +#ifdef __debug__ Print("DXShaderInputsSet: LastError: ", GetLastError()); +#endif } DXInputSet(cbuffer_handle, data); +#ifdef __debug__ Print("DXInputSet: LastError: ", GetLastError()); +#endif } /** * Selectes shader to be used by graphics device for rendering. */ virtual void Select() { - // Setting MVP transform. - mvp_buffer.world = GetDevice().GetWorldMatrix(); - mvp_buffer.view = GetDevice().GetViewMatrix(); - mvp_buffer.projection = GetDevice().GetProjectionMatrix(); + // Setting MVP transform and material information. + + DXMatrixTranspose(mvp_buffer.world, GetDevice().GetWorldMatrix()); + DXMatrixTranspose(mvp_buffer.view, GetDevice().GetViewMatrix()); + DXMatrixTranspose(mvp_buffer.projection, GetDevice().GetProjectionMatrix()); mvp_buffer.lightdir = GetDevice().GetLightDirection(); + mvp_buffer.mat_color = GetDevice().GetMaterial().Color; if (cbuffer_handle == 0) { int _input_handles[1]; @@ -171,7 +189,9 @@ class MTDXShader : public Shader { DXShaderInputsSet(handle, _input_handles); } +#ifdef __debug__ Print("DXShaderInputsSet: LastError: ", GetLastError()); +#endif DXInputSet(cbuffer_mvp_handle, mvp_buffer); DXShaderSet(GetDevice().Context(), handle); diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index c3cf7fdda..915d60979 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -44,14 +44,20 @@ class MTDXVertexBuffer : public VertexBuffer { template bool Fill(X& _data[]) { handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_VERTEX, _data); +#ifdef __debug__ Print("Created vb ", handle); Print("Fill: LastError: ", GetLastError()); +#endif return true; } virtual void Select() { +#ifdef __debug__ Print("Selecting vb ", handle); +#endif DXBufferSet(GetDevice().Context(), handle); +#ifdef __debug__ Print("Select: LastError: ", GetLastError()); +#endif } }; \ No newline at end of file diff --git a/3D/Face.h b/3D/Face.h index 7f7ad38af..76b87e26b 100644 --- a/3D/Face.h +++ b/3D/Face.h @@ -89,8 +89,6 @@ struct Face { DXVec3Cross(_normal, _v1, _v2); DXVec3Normalize(_normal, _normal); - // Print("cross = ", _normal.x, ", ", _normal.y, ", ", _normal.z); - for (int i = 0; i < 4; ++i) { points[i].Normal = _normal; } diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 357b4266a..6c88f1347 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -52,19 +52,23 @@ class MT5Frontend : public Frontend { ChartSetInteger(0, CHART_SHOW, false); ChartRedraw(); - Print("LastError: ", GetLastError()); +#ifdef __debug__ + Print("MT5 Frontend: LastError: ", GetLastError()); +#endif objname = "MT5_Frontend_" + IntegerToString(ChartID()); resname = "::MT5_Frontend" + IntegerToString(ChartID()); ObjectCreate(0, objname, OBJ_BITMAP_LABEL, 0, 0, 0); ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 0); ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 0); - Print("LastError: ", GetLastError()); - - Print("LastError: ", GetLastError()); +#ifdef __debug__ + Print("MT5 Frontend: ObjectCreate/Set: LastError: ", GetLastError()); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); +#endif ObjectSetString(ChartID(), objname, OBJPROP_BMPFILE, resname); +#ifdef __debug__ Print("LastError: ", GetLastError()); +#endif return true; } @@ -88,9 +92,13 @@ class MT5Frontend : public Frontend { } ArrayResize(image, Width() * Height()); +#ifdef __debug__ Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); +#endif ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); +#ifdef __debug__ Print("ResourceCreate: LastError: ", GetLastError()); +#endif last_width = Width(); last_height = Height(); @@ -102,27 +110,37 @@ class MT5Frontend : public Frontend { * Executed before render starts. */ virtual void RenderBegin(int context) { +#ifdef __debug__ Print("MT5Frontend: RenderBegin()"); Print("Image resize: width = ", Width(), ", height = ", Height()); +#endif if (Resize()) { DXContextSetSize(context, Width(), Height()); } +#ifdef __debug__ Print("DXContextSetSize: LastError: ", GetLastError()); +#endif } /** * Executed after render ends. */ virtual void RenderEnd(int context) { +#ifdef __debug__ Print("MT5Frontend: RenderEnd()"); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); Print("MT5Frontend: DXContextGetColors()"); +#endif DXContextGetColors(context, image); +#ifdef __debug__ Print("DXContextGetColors: LastError: ", GetLastError()); +#endif ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); +#ifdef __debug__ Print("ResourceCreate: LastError: ", GetLastError()); +#endif ChartRedraw(); Sleep(5); } diff --git a/3D/Math.h b/3D/Math.h index f4ca30204..ae74f4092 100644 --- a/3D/Math.h +++ b/3D/Math.h @@ -72,6 +72,12 @@ struct DXColor { b = v.z; a = 1.0; } + DXColor(unsigned int _color) { + a = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); + r = 1.0f / 255.0f * ((_color & 0x00FF0000) >> 16); + g = 1.0f / 255.0f * ((_color & 0x0000FF00) >> 8); + b = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); + } }; //+------------------------------------------------------------------+ //| DXPlane | @@ -352,7 +358,7 @@ Bintensity,float &rout[],float &gout[],float &bout[]); int DXSHEvalHemisphereL order,const DXVector3 &dir,float radius,float Rintensity,float Gintensity,float Bintensity,float &rout[],float &gout[],float &bout[]); void DXSHMultiply2(float &out[],const float &a[],const float &b[]); void DXSHMultiply3(float &out[],const float &a[],const float &b[]); void DXSHMultiply4(float &out[],const float &a[],const float &b[]); void -DXSHRotate(float &out[],int order,const DXMatrix &matrix,const float &in[]); void DXSHRotateZ(float &out[],int +DXSHRotate(float &out[],int order,const DXMatrix &_matrix,const float &in[]); void DXSHRotateZ(float &out[],int order,float angle,const float &in[]); void DXSHScale(float &out[],int order,const float &a[],const float scale); //--- scalar functions @@ -627,8 +633,8 @@ void DXVec2Subtract(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) pout.y = pv1.y - pv2.y; } //+------------------------------------------------------------------+ -//| Transforms a 2D vector by a given matrix. | -//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//| Transforms a 2D vector by a given _matrix. | +//| This function transforms the vector pv(x,y,0,1) by the _matrix pm.| //+------------------------------------------------------------------+ void DXVec2Transform(DXVector4 &pout, const DXVector2 &pv, const DXMatrix &pm) { DXVector4 out; @@ -639,9 +645,9 @@ void DXVec2Transform(DXVector4 &pout, const DXVector2 &pv, const DXMatrix &pm) { pout = out; } //+------------------------------------------------------------------+ -//| Transforms a 2D vector by a given matrix, | +//| Transforms a 2D vector by a given _matrix, | //| projecting the result back into w = 1. | -//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//| This function transforms the vector pv(x,y,0,1) by the _matrix pm.| //+------------------------------------------------------------------+ void DXVec2TransformCoord(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { float norm = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[3][3]; @@ -654,7 +660,7 @@ void DXVec2TransformCoord(DXVector2 &pout, const DXVector2 &pv, const DXMatrix & } } //+------------------------------------------------------------------+ -//| Transforms the 2D vector normal by the given matrix. | +//| Transforms the 2D vector normal by the given _matrix. | //+------------------------------------------------------------------+ void DXVec2TransformNormal(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y; @@ -804,7 +810,7 @@ void DXVec3Subtract(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) pout.z = pv1.z - pv2.z; } //+------------------------------------------------------------------+ -//| Transforms vector (x,y,z,1) by a given matrix. | +//| Transforms vector (x,y,z,1) by a given _matrix. | //+------------------------------------------------------------------+ void DXVec3Transform(DXVector4 &pout, const DXVector3 &pv, const DXMatrix &pm) { DXVector4 out; @@ -816,7 +822,7 @@ void DXVec3Transform(DXVector4 &pout, const DXVector3 &pv, const DXMatrix &pm) { pout = out; } //+------------------------------------------------------------------+ -//| Transforms a 3D vector by a given matrix, | +//| Transforms a 3D vector by a given _matrix, | //| projecting the result back into w = 1. | //+------------------------------------------------------------------+ void DXVec3TransformCoord(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { @@ -833,7 +839,7 @@ void DXVec3TransformCoord(DXVector3 &pout, const DXVector3 &pv, const DXMatrix & } } //+------------------------------------------------------------------+ -//| Transforms the 3D vector normal by the given matrix. | +//| Transforms the 3D vector normal by the given _matrix. | //+------------------------------------------------------------------+ void DXVec3TransformNormal(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z; @@ -853,7 +859,7 @@ void DXVec3Unproject(DXVector3 &out, const DXVector3 &v, const DViewport &viewpo DXMatrixMultiply(m, m, view); //--- projection DXMatrixMultiply(m, m, projection); - //--- calculate inverse matrix + //--- calculate inverse _matrix float det = 0.0f; DXMatrixInverse(m, det, m); out = v; @@ -1009,7 +1015,7 @@ void DXVec4Subtract(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) pout.w = pv1.w - pv2.w; } //+------------------------------------------------------------------+ -//| Transforms a 4D vector by a given matrix. | +//| Transforms a 4D vector by a given _matrix. | //+------------------------------------------------------------------+ void DXVec4Transform(DXVector4 &pout, const DXVector4 &pv, const DXMatrix &pm) { DXVector4 temp; @@ -1154,7 +1160,7 @@ void DXQuaternionRotationAxis(DXQuaternion &out, const DXVector3 &v, float angle out.w = (float)cos(angle / 2.0f); } //+------------------------------------------------------------------+ -//| Builds a quaternion from a rotation matrix. | +//| Builds a quaternion from a rotation _matrix. | //+------------------------------------------------------------------+ void DXQuaternionRotationMatrix(DXQuaternion &out, const DXMatrix &m) { float s; @@ -1324,7 +1330,7 @@ void DXQuaternionToAxisAngle(const DXQuaternion &pq, DXVector3 &paxis, float &pa pangle = 2.0f * (float)acos(pq.w); } //+------------------------------------------------------------------+ -//| DXMatrixIdentity creates an identity matrix | +//| DXMatrixIdentity creates an identity _matrix | //+------------------------------------------------------------------+ void DXMatrixIdentity(DXMatrix &out) { for (int j = 0; j < 4; j++) @@ -1336,7 +1342,7 @@ void DXMatrixIdentity(DXMatrix &out) { } } //+------------------------------------------------------------------+ -//| Determines if a matrix is an identity matrix. | +//| Determines if a _matrix is an identity _matrix. | //+------------------------------------------------------------------+ bool DXMatrixIsIdentity(DXMatrix &pm) { for (int j = 0; j < 4; j++) @@ -1350,18 +1356,18 @@ bool DXMatrixIsIdentity(DXMatrix &pm) { return (true); } //+------------------------------------------------------------------+ -//| Builds a 3D affine transformation matrix. | +//| Builds a 3D affine transformation _matrix. | //+------------------------------------------------------------------+ -//| This function calculates the affine transformation matrix | -//| with the following formula, with matrix concatenation | +//| This function calculates the affine transformation _matrix | +//| with the following formula, with _matrix concatenation | //| evaluated in left-to-right order: | //| Mout = Ms * (Mrc)-1 * Mr * Mrc * Mt | //| where: | -//| Mout = output matrix (pOut) | -//| Ms = scaling matrix (Scaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (pRotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Ms = scaling _matrix (Scaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (pRotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixAffineTransformation(DXMatrix &out, float scaling, const DXVector3 &rotationcenter, const DXQuaternion &rotation, const DXVector3 &translation) { @@ -1396,18 +1402,18 @@ void DXMatrixAffineTransformation(DXMatrix &out, float scaling, const DXVector3 out.m[3][2] += translation.z; } //+------------------------------------------------------------------+ -//| Builds a 2D affine transformation matrix in the xy plane. | +//| Builds a 2D affine transformation _matrix in the xy plane. | //+------------------------------------------------------------------+ -//| This function calculates the affine transformation matrix | -//| with the following formula, with matrix concatenation evaluated | +//| This function calculates the affine transformation _matrix | +//| with the following formula, with _matrix concatenation evaluated | //| in left-to-right order: | //| Mout = Ms * (Mrc)^(-1) * Mr * Mrc * Mt | //| where: | -//| Mout = output matrix (pOut) | -//| Ms = scaling matrix (Scaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (Rotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Ms = scaling _matrix (Scaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (Rotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector2 &rotationcenter, float rotation, const DXVector2 &translation) { @@ -1432,7 +1438,7 @@ void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector #define D3DERR_INVALIDCALL -2005530516 //#define S_OK 0; //+------------------------------------------------------------------+ -//| Breaks down a general 3D transformation matrix into its scalar, | +//| Breaks down a general 3D transformation _matrix into its scalar, | //| rotational, and translational components. | //+------------------------------------------------------------------+ int DXMatrixDecompose(DXVector3 &poutscale, DXQuaternion &poutrotation, DXVector3 &pouttranslation, @@ -1473,7 +1479,7 @@ int DXMatrixDecompose(DXVector3 &poutscale, DXQuaternion &poutrotation, DXVector return (0); } //+------------------------------------------------------------------+ -//| Returns the determinant of a matrix. | +//| Returns the determinant of a _matrix. | //+------------------------------------------------------------------+ float DXMatrixDeterminant(const DXMatrix &pm) { float t[3], v[4]; @@ -1492,7 +1498,7 @@ float DXMatrixDeterminant(const DXMatrix &pm) { return (pm.m[0][0] * v[0] + pm.m[0][1] * v[1] + pm.m[0][2] * v[2] + pm.m[0][3] * v[3]); } //+------------------------------------------------------------------+ -//| Calculates the inverse of a matrix. | +//| Calculates the inverse of a _matrix. | //+------------------------------------------------------------------+ void DXMatrixInverse(DXMatrix &pout, float &pdeterminant, const DXMatrix &pm) { float t[3], v[16]; @@ -1562,9 +1568,9 @@ void DXMatrixInverse(DXMatrix &pout, float &pdeterminant, const DXMatrix &pm) { for (int j = 0; j < 4; j++) pout.m[i][j] = v[4 * i + j] * det; } //+------------------------------------------------------------------+ -//| Builds a left-handed,look-at matrix. | +//| Builds a left-handed,look-at _matrix. | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| | //| zaxis = normal(At - Eye) | //| xaxis = normal(cross(Up,zaxis)) | @@ -1602,10 +1608,10 @@ void DXMatrixLookAtLH(DXMatrix &out, const DXVector3 &eye, const DXVector3 &at, out.m[3][3] = 1.0f; } //+------------------------------------------------------------------+ -//| Builds a right-handed, look-at matrix. | +//| Builds a right-handed, look-at _matrix. | //+------------------------------------------------------------------+ //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| | //| zaxis = normal(Eye - At) | //| xaxis = normal(cross(Up,zaxis)) | @@ -1667,7 +1673,7 @@ void DXMatrixMultiplyTranspose(DXMatrix &pout, const DXMatrix &pm1, const DXMatr pout = temp; } //+------------------------------------------------------------------+ -//| Builds a left-handed orthographic projection matrix. | +//| Builds a left-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ void DXMatrixOrthoLH(DXMatrix &pout, float w, float h, float zn, float zf) { DXMatrixIdentity(pout); @@ -1678,7 +1684,7 @@ void DXMatrixOrthoLH(DXMatrix &pout, float w, float h, float zn, float zf) { pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a customized,left-handed orthographic projection matrix. | +//| Builds a customized,left-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ void DXMatrixOrthoOffCenterLH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { DXMatrixIdentity(pout); @@ -1691,7 +1697,7 @@ void DXMatrixOrthoOffCenterLH(DXMatrix &pout, float l, float r, float b, float t pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a customized,right-handed orthographic projection matrix. | +//| Builds a customized,right-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ void DXMatrixOrthoOffCenterRH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { DXMatrixIdentity(pout); @@ -1704,14 +1710,14 @@ void DXMatrixOrthoOffCenterRH(DXMatrix &pout, float l, float r, float b, float t pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a right-handed orthographic projection matrix. | +//| Builds a right-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixOrthoRH function | //| are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix: | +//| the returned _matrix: | //| 2/w 0 0 0 | //| 0 2/h 0 0 | //| 0 0 1/(zn-zf) 0 | @@ -1725,10 +1731,10 @@ void DXMatrixOrthoRH(DXMatrix &pout, float w, float h, float zn, float zf) { pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a left-handed perspective projection matrix | +//| Builds a left-handed perspective projection _matrix | //| based on a field of view. | //+------------------------------------------------------------------+ -//| This function computes the returned matrix as shown: | +//| This function computes the returned _matrix as shown: | //| xScale 0 0 0 | //| 0 yScale 0 0 | //| 0 0 zf/(zf-zn) 1 | @@ -1748,10 +1754,10 @@ void DXMatrixPerspectiveFovLH(DXMatrix &pout, float fovy, float aspect, float zn pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a right-handed perspective projection matrix | +//| Builds a right-handed perspective projection _matrix | //| based on a field of view. | //+------------------------------------------------------------------+ -//| This function computes the returned matrix as shown. | +//| This function computes the returned _matrix as shown. | //| xScale 0 0 0 | //| 0 yScale 0 0 | //| 0 0 zf/(zn-zf) -1 | @@ -1771,10 +1777,10 @@ void DXMatrixPerspectiveFovRH(DXMatrix &pout, float fovy, float aspect, float zn pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a left-handed perspective projection matrix | +//| Builds a left-handed perspective projection _matrix | //+------------------------------------------------------------------+ //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/w 0 0 0 | //| 0 2*zn/h 0 0 | //| 0 0 zf/(zf-zn) 1 | @@ -1790,14 +1796,14 @@ void DXMatrixPerspectiveLH(DXMatrix &pout, float w, float h, float zn, float zf) pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a customized, left-handed perspective projection matrix. | +//| Builds a customized, left-handed perspective projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixPerspectiveOffCenterLH | //| function are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/(r-l) 0 0 0 | //| 0 2*zn/(t-b) 0 0 | //| (l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1 | @@ -1816,14 +1822,14 @@ void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout, float l, float r, float b, f pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a customized, right-handed perspective projection matrix. | +//| Builds a customized, right-handed perspective projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixPerspectiveOffCenterRH | //| function are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/(r-l) 0 0 0 | //| 0 2*zn/(t-b) 0 0 | //| (l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1 | @@ -1842,14 +1848,14 @@ void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout, float l, float r, float b, f pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a right-handed perspective projection matrix. | +//| Builds a right-handed perspective projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixPerspectiveRH function | //| are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/w 0 0 0 | //| 0 2*zn/h 0 0 | //| 0 0 zf/(zn-zf) -1 | @@ -1866,12 +1872,12 @@ void DXMatrixPerspectiveRH(DXMatrix &pout, float w, float h, float zn, float zf) pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a matrix that reflects the coordinate system about a plane| +//| Builds a _matrix that reflects the coordinate system about a plane| //| This function normalizes the plane equation before it creates | -//| the reflected matrix. | +//| the reflected _matrix. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| P = normalize(Plane); | //| -2 * P.a * P.a + 1 -2 * P.b * P.a -2 * P.c * P.a 0 | //| -2 * P.a * P.b -2 * P.b * P.b + 1 -2 * P.c * P.b 0 | @@ -1897,7 +1903,7 @@ void DXMatrixReflect(DXMatrix &pout, const DXPlane &pplane) { pout.m[3][2] = -2.0f * Nplane.d * Nplane.c; } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around an arbitrary axis. | +//| Builds a _matrix that rotates around an arbitrary axis. | //+------------------------------------------------------------------+ void DXMatrixRotationAxis(DXMatrix &out, const DXVector3 &v, float angle) { DXVector3 nv; @@ -1925,7 +1931,7 @@ void DXMatrixRotationAxis(DXMatrix &out, const DXVector3 &v, float angle) { out.m[3][3] = 1.0f; } //+------------------------------------------------------------------+ -//| Builds a rotation matrix from a quaternion. | +//| Builds a rotation _matrix from a quaternion. | //+------------------------------------------------------------------+ void DXMatrixRotationQuaternion(DXMatrix &pout, const DXQuaternion &pq) { DXMatrixIdentity(pout); @@ -1941,7 +1947,7 @@ void DXMatrixRotationQuaternion(DXMatrix &pout, const DXQuaternion &pq) { pout.m[2][2] = 1.0f - 2.0f * (pq.x * pq.x + pq.y * pq.y); } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the x-axis. | +//| Builds a _matrix that rotates around the x-axis. | //+------------------------------------------------------------------+ void DXMatrixRotationX(DXMatrix &pout, float angle) { DXMatrixIdentity(pout); @@ -1952,7 +1958,7 @@ void DXMatrixRotationX(DXMatrix &pout, float angle) { pout.m[2][1] = -(float)sin(angle); } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the y-axis. | +//| Builds a _matrix that rotates around the y-axis. | //+------------------------------------------------------------------+ void DXMatrixRotationY(DXMatrix &pout, float angle) { DXMatrixIdentity(pout); @@ -1963,7 +1969,7 @@ void DXMatrixRotationY(DXMatrix &pout, float angle) { pout.m[2][0] = (float)sin(angle); } //+------------------------------------------------------------------+ -//| Builds a matrix with a specified yaw, pitch, and roll. | +//| Builds a _matrix with a specified yaw, pitch, and roll. | //+------------------------------------------------------------------+ //| The order of transformations is roll first, then pitch, then yaw.| //| Relative to the object's local coordinate axis, this is | @@ -1996,7 +2002,7 @@ void DXMatrixRotationYawPitchRoll(DXMatrix &out, float yaw, float pitch, float r out.m[3][3] = 1.0f; } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the z-axis. | +//| Builds a _matrix that rotates around the z-axis. | //+------------------------------------------------------------------+ void DXMatrixRotationZ(DXMatrix &pout, float angle) { DXMatrixIdentity(pout); @@ -2007,7 +2013,7 @@ void DXMatrixRotationZ(DXMatrix &pout, float angle) { pout.m[1][0] = -(float)sin(angle); } //+------------------------------------------------------------------+ -//| Builds a matrix that scales along the x-axis, | +//| Builds a _matrix that scales along the x-axis, | //| the y-axis,and the z-axis. | //+------------------------------------------------------------------+ void DXMatrixScaling(DXMatrix &pout, float sx, float sy, float sz) { @@ -2017,12 +2023,12 @@ void DXMatrixScaling(DXMatrix &pout, float sx, float sy, float sz) { pout.m[2][2] = sz; } //+------------------------------------------------------------------+ -//| Builds a matrix that flattens geometry into a plane. | +//| Builds a _matrix that flattens geometry into a plane. | //+------------------------------------------------------------------+ //| The DXMatrixShadow function flattens geometry into a plane, as | //| if casting a shadow from a light. | //| This function uses the following formula to compute the returned | -//| matrix. | +//| _matrix. | //| | //| P = normalize(Plane); | //| L = Light; | @@ -2060,22 +2066,22 @@ void DXMatrixShadow(DXMatrix &pout, const DXVector4 &plight, const DXPlane &ppla pout.m[3][3] = dot - Nplane.d * plight.w; } //+------------------------------------------------------------------+ -//| Builds a transformation matrix. | +//| Builds a transformation _matrix. | //+------------------------------------------------------------------+ -//| This function calculates the transformation matrix with the | -//| following formula, with matrix concatenation evaluated | +//| This function calculates the transformation _matrix with the | +//| following formula, with _matrix concatenation evaluated | //| in left-to-right order: | //| | //| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | //| | //| where: | -//| Mout = output matrix (pOut) | -//| Msc = scaling center matrix (pScalingCenter) | -//| Msr = scaling rotation matrix (pScalingRotation) | -//| Ms = scaling matrix (pScaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (pRotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Msc = scaling center _matrix (pScalingCenter) | +//| Msr = scaling rotation _matrix (pScalingRotation) | +//| Ms = scaling _matrix (pScaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (pRotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixTransformation(DXMatrix &pout, const DXVector3 &pscalingcenter, const DXQuaternion &pscalingrotation, const DXVector3 &pscaling, const DXVector3 &protationcenter, const DXQuaternion &protation, @@ -2119,23 +2125,23 @@ void DXMatrixTransformation(DXMatrix &pout, const DXVector3 &pscalingcenter, con DXMatrixMultiply(pout, m1, m7); } //+------------------------------------------------------------------+ -//| Builds a 2D transformation matrix that represents | +//| Builds a 2D transformation _matrix that represents | //| transformations in the xy plane. | //+------------------------------------------------------------------+ -//| This function calculates the transformation matrix with the | -//| following formula, with matrix concatenation evaluated | +//| This function calculates the transformation _matrix with the | +//| following formula, with _matrix concatenation evaluated | //| in left-to-right order: | //| | //| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | //| | //| where: | -//| Mout = output matrix (pOut) | -//| Msc = scaling center matrix (pScalingCenter) | -//| Msr = scaling rotation matrix (pScalingRotation) | -//| Ms = scaling matrix (pScaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (Rotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Msc = scaling center _matrix (pScalingCenter) | +//| Msr = scaling rotation _matrix (pScalingRotation) | +//| Ms = scaling _matrix (pScaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (Rotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixTransformation2D(DXMatrix &pout, const DXVector2 &pscalingcenter, float scalingrotation, const DXVector2 &pscaling, const DXVector2 &protationcenter, float rotation, @@ -2171,7 +2177,7 @@ void DXMatrixTransformation2D(DXMatrix &pout, const DXVector2 &pscalingcenter, f DXMatrixTransformation(pout, sca_center, sca_rot, sca, rot_center, rot, trans); } //+------------------------------------------------------------------+ -//| Builds a matrix using the specified offsets. | +//| Builds a _matrix using the specified offsets. | //+------------------------------------------------------------------+ void DXMatrixTranslation(DXMatrix &pout, float x, float y, float z) { DXMatrixIdentity(pout); @@ -2181,7 +2187,7 @@ void DXMatrixTranslation(DXMatrix &pout, float x, float y, float z) { pout.m[3][2] = z; } //+------------------------------------------------------------------+ -//| Returns the matrix transpose of a matrix. | +//| Returns the _matrix transpose of a _matrix. | //+------------------------------------------------------------------+ void DXMatrixTranspose(DXMatrix &pout, const DXMatrix &pm) { const DXMatrix m = pm; @@ -2287,8 +2293,8 @@ void DXPlaneScale(DXPlane &pout, const DXPlane &p, float s) { pout.d = p.d * s; }; //+------------------------------------------------------------------+ -//| Transforms a plane by a matrix. | -//| The input matrix is the inverse transpose of the actual | +//| Transforms a plane by a _matrix. | +//| The input _matrix is the inverse transpose of the actual | //| transformation. | //+------------------------------------------------------------------+ void DXPlaneTransform(DXPlane &pout, const DXPlane &pplane, const DXMatrix &pm) { @@ -3068,7 +3074,7 @@ void rotate_X(float &out[], uint order, float a, float &in[]) { out[35] = 0.9057110548f * in[31] - 0.4192627370f * in[33] + 0.0624999329f * in[35]; } //+------------------------------------------------------------------+ -//| Rotates the spherical harmonic (SH) vector by the given matrix. | +//| Rotates the spherical harmonic (SH) vector by the given _matrix. | //+------------------------------------------------------------------+ //| Each coefficient of the basis function Y(l,m) | //| is stored at memory location l^2 + m + l, where: | @@ -3076,57 +3082,57 @@ void rotate_X(float &out[], uint order, float a, float &in[]) { //| m is the basis function index for the given l value | //| and ranges from -l to l, inclusive. | //+------------------------------------------------------------------+ -void DXSHRotate(float &out[], int order, const DXMatrix &matrix, const float &in[]) { +void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &in[]) { float alpha, beta, gamma, sinb, temp[36], temp1[36]; out[0] = in[0]; if ((order > DXSH_MAXORDER) || (order < DXSH_MINORDER)) return; if (order <= 3) { - out[1] = matrix.m[1][1] * in[1] - matrix.m[2][1] * in[2] + matrix.m[0][1] * in[3]; - out[2] = -matrix.m[1][2] * in[1] + matrix.m[2][2] * in[2] - matrix.m[0][2] * in[3]; - out[3] = matrix.m[1][0] * in[1] - matrix.m[2][0] * in[2] + matrix.m[0][0] * in[3]; + out[1] = _matrix.m[1][1] * in[1] - _matrix.m[2][1] * in[2] + _matrix.m[0][1] * in[3]; + out[2] = -_matrix.m[1][2] * in[1] + _matrix.m[2][2] * in[2] - _matrix.m[0][2] * in[3]; + out[3] = _matrix.m[1][0] * in[1] - _matrix.m[2][0] * in[2] + _matrix.m[0][0] * in[3]; if (order == 3) { float coeff[12] = {}; - coeff[0] = matrix.m[1][0] * matrix.m[0][0]; - coeff[1] = matrix.m[1][1] * matrix.m[0][1]; - coeff[2] = matrix.m[1][1] * matrix.m[2][1]; - coeff[3] = matrix.m[1][0] * matrix.m[2][0]; - coeff[4] = matrix.m[2][0] * matrix.m[2][0]; - coeff[5] = matrix.m[2][1] * matrix.m[2][1]; - coeff[6] = matrix.m[0][0] * matrix.m[2][0]; - coeff[7] = matrix.m[0][1] * matrix.m[2][1]; - coeff[8] = matrix.m[0][1] * matrix.m[0][1]; - coeff[9] = matrix.m[1][0] * matrix.m[1][0]; - coeff[10] = matrix.m[1][1] * matrix.m[1][1]; - coeff[11] = matrix.m[0][0] * matrix.m[0][0]; - - out[4] = (matrix.m[1][1] * matrix.m[0][0] + matrix.m[0][1] * matrix.m[1][0]) * in[4]; - out[4] -= (matrix.m[1][0] * matrix.m[2][1] + matrix.m[1][1] * matrix.m[2][0]) * in[5]; - out[4] += 1.7320508076f * matrix.m[2][0] * matrix.m[2][1] * in[6]; - out[4] -= (matrix.m[0][1] * matrix.m[2][0] + matrix.m[0][0] * matrix.m[2][1]) * in[7]; - out[4] += (matrix.m[0][0] * matrix.m[0][1] - matrix.m[1][0] * matrix.m[1][1]) * in[8]; - - out[5] = (matrix.m[1][1] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][1]) * in[5]; - out[5] -= (matrix.m[1][1] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][1]) * in[4]; - out[5] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][1] * in[6]; - out[5] += (matrix.m[0][2] * matrix.m[2][1] + matrix.m[0][1] * matrix.m[2][2]) * in[7]; - out[5] -= (matrix.m[0][1] * matrix.m[0][2] - matrix.m[1][1] * matrix.m[1][2]) * in[8]; - - out[6] = (matrix.m[2][2] * matrix.m[2][2] - 0.5f * (coeff[4] + coeff[5])) * in[6]; - out[6] -= (0.5773502692f * (coeff[0] + coeff[1]) - 1.1547005384f * matrix.m[1][2] * matrix.m[0][2]) * in[4]; - out[6] += (0.5773502692f * (coeff[2] + coeff[3]) - 1.1547005384f * matrix.m[1][2] * matrix.m[2][2]) * in[5]; - out[6] += (0.5773502692f * (coeff[6] + coeff[7]) - 1.1547005384f * matrix.m[0][2] * matrix.m[2][2]) * in[7]; + coeff[0] = _matrix.m[1][0] * _matrix.m[0][0]; + coeff[1] = _matrix.m[1][1] * _matrix.m[0][1]; + coeff[2] = _matrix.m[1][1] * _matrix.m[2][1]; + coeff[3] = _matrix.m[1][0] * _matrix.m[2][0]; + coeff[4] = _matrix.m[2][0] * _matrix.m[2][0]; + coeff[5] = _matrix.m[2][1] * _matrix.m[2][1]; + coeff[6] = _matrix.m[0][0] * _matrix.m[2][0]; + coeff[7] = _matrix.m[0][1] * _matrix.m[2][1]; + coeff[8] = _matrix.m[0][1] * _matrix.m[0][1]; + coeff[9] = _matrix.m[1][0] * _matrix.m[1][0]; + coeff[10] = _matrix.m[1][1] * _matrix.m[1][1]; + coeff[11] = _matrix.m[0][0] * _matrix.m[0][0]; + + out[4] = (_matrix.m[1][1] * _matrix.m[0][0] + _matrix.m[0][1] * _matrix.m[1][0]) * in[4]; + out[4] -= (_matrix.m[1][0] * _matrix.m[2][1] + _matrix.m[1][1] * _matrix.m[2][0]) * in[5]; + out[4] += 1.7320508076f * _matrix.m[2][0] * _matrix.m[2][1] * in[6]; + out[4] -= (_matrix.m[0][1] * _matrix.m[2][0] + _matrix.m[0][0] * _matrix.m[2][1]) * in[7]; + out[4] += (_matrix.m[0][0] * _matrix.m[0][1] - _matrix.m[1][0] * _matrix.m[1][1]) * in[8]; + + out[5] = (_matrix.m[1][1] * _matrix.m[2][2] + _matrix.m[1][2] * _matrix.m[2][1]) * in[5]; + out[5] -= (_matrix.m[1][1] * _matrix.m[0][2] + _matrix.m[1][2] * _matrix.m[0][1]) * in[4]; + out[5] -= 1.7320508076f * _matrix.m[2][2] * _matrix.m[2][1] * in[6]; + out[5] += (_matrix.m[0][2] * _matrix.m[2][1] + _matrix.m[0][1] * _matrix.m[2][2]) * in[7]; + out[5] -= (_matrix.m[0][1] * _matrix.m[0][2] - _matrix.m[1][1] * _matrix.m[1][2]) * in[8]; + + out[6] = (_matrix.m[2][2] * _matrix.m[2][2] - 0.5f * (coeff[4] + coeff[5])) * in[6]; + out[6] -= (0.5773502692f * (coeff[0] + coeff[1]) - 1.1547005384f * _matrix.m[1][2] * _matrix.m[0][2]) * in[4]; + out[6] += (0.5773502692f * (coeff[2] + coeff[3]) - 1.1547005384f * _matrix.m[1][2] * _matrix.m[2][2]) * in[5]; + out[6] += (0.5773502692f * (coeff[6] + coeff[7]) - 1.1547005384f * _matrix.m[0][2] * _matrix.m[2][2]) * in[7]; out[6] += (0.2886751347f * (coeff[9] - coeff[8] + coeff[10] - coeff[11]) - - 0.5773502692f * (matrix.m[1][2] * matrix.m[1][2] - matrix.m[0][2] * matrix.m[0][2])) * + 0.5773502692f * (_matrix.m[1][2] * _matrix.m[1][2] - _matrix.m[0][2] * _matrix.m[0][2])) * in[8]; - out[7] = (matrix.m[0][0] * matrix.m[2][2] + matrix.m[0][2] * matrix.m[2][0]) * in[7]; - out[7] -= (matrix.m[1][0] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][0]) * in[4]; - out[7] += (matrix.m[1][0] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][0]) * in[5]; - out[7] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][0] * in[6]; - out[7] -= (matrix.m[0][0] * matrix.m[0][2] - matrix.m[1][0] * matrix.m[1][2]) * in[8]; + out[7] = (_matrix.m[0][0] * _matrix.m[2][2] + _matrix.m[0][2] * _matrix.m[2][0]) * in[7]; + out[7] -= (_matrix.m[1][0] * _matrix.m[0][2] + _matrix.m[1][2] * _matrix.m[0][0]) * in[4]; + out[7] += (_matrix.m[1][0] * _matrix.m[2][2] + _matrix.m[1][2] * _matrix.m[2][0]) * in[5]; + out[7] -= 1.7320508076f * _matrix.m[2][2] * _matrix.m[2][0] * in[6]; + out[7] -= (_matrix.m[0][0] * _matrix.m[0][2] - _matrix.m[1][0] * _matrix.m[1][2]) * in[8]; out[8] = 0.5f * (coeff[11] - coeff[8] - coeff[9] + coeff[10]) * in[8]; out[8] += (coeff[0] - coeff[1]) * in[4]; @@ -3137,13 +3143,13 @@ void DXSHRotate(float &out[], int order, const DXMatrix &matrix, const float &in return; } - if ((float)fabs(matrix.m[2][2]) != 1.0f) { - sinb = (float)sqrt(1.0f - matrix.m[2][2] * matrix.m[2][2]); - alpha = (float)atan2(matrix.m[2][1] / sinb, matrix.m[2][0] / sinb); - beta = (float)atan2(sinb, matrix.m[2][2]); - gamma = (float)atan2(matrix.m[1][2] / sinb, -matrix.m[0][2] / sinb); + if ((float)fabs(_matrix.m[2][2]) != 1.0f) { + sinb = (float)sqrt(1.0f - _matrix.m[2][2] * _matrix.m[2][2]); + alpha = (float)atan2(_matrix.m[2][1] / sinb, _matrix.m[2][0] / sinb); + beta = (float)atan2(sinb, _matrix.m[2][2]); + gamma = (float)atan2(_matrix.m[1][2] / sinb, -_matrix.m[0][2] / sinb); } else { - alpha = (float)atan2(matrix.m[0][1], matrix.m[0][0]); + alpha = (float)atan2(_matrix.m[0][1], _matrix.m[0][0]); beta = 0.0f; gamma = 0.0f; } diff --git a/3D/Mesh.h b/3D/Mesh.h index 681a63851..94b8e9f0a 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -30,6 +30,7 @@ #include "../Util.h" #include "Face.h" #include "IndexBuffer.h" +#include "Material.h" #include "Math.h" #include "TSR.h" #include "VertexBuffer.h" @@ -74,6 +75,7 @@ class Mesh : public Dynamic { TSR tsr; ENUM_MESH_TYPE type; bool initialized; + Material material; public: /** @@ -89,6 +91,10 @@ class Mesh : public Dynamic { */ virtual void Initialize(Device* _device) {} + TSR* GetTSR() { return &tsr; } + + void SetTSR(const TSR& _tsr) { tsr = _tsr; } + /** * Adds a single 3 or 4-vertex face. */ @@ -97,6 +103,16 @@ class Mesh : public Dynamic { Util::ArrayPush(faces, face, 16); } + /** + * Returns material assigned to mesh. + */ + Material* GetMaterial() { return &material; } + + /** + * Assigns material to mesh. + */ + void SetMaterial(Material& _material) { material = _material; } + /** * Returns vertex shader for mesh rendering. */ @@ -128,7 +144,9 @@ class Mesh : public Dynamic { initialized = true; } +#ifdef __debug__ Print("Getting buffers. Mesh type = ", EnumToString(type)); +#endif if (vbuff.IsSet() && ibuff.IsSet()) { _vbuff = vbuff.Ptr(); _ibuff = ibuff.Ptr(); @@ -205,8 +223,8 @@ class Mesh : public Dynamic { _s_vertices += "["; _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position.x) + ", " + DoubleToString(_vertices[i].Position.y) + "," + DoubleToString(_vertices[i].Position.z) + " | "; - _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color.x) + ", " + DoubleToString(_vertices[i].Color.y) + - "," + DoubleToString(_vertices[i].Color.z) + "," + DoubleToString(_vertices[i].Color.w); + _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color.r) + ", " + DoubleToString(_vertices[i].Color.g) + + "," + DoubleToString(_vertices[i].Color.b) + "," + DoubleToString(_vertices[i].Color.a); _s_vertices += "]"; if (i != ArraySize(_vertices) - 1) { _s_vertices += ", "; @@ -226,8 +244,10 @@ class Mesh : public Dynamic { _s_indices += "]"; +#ifdef __debug__ Print("Vertices: ", _s_vertices); Print("Indices: ", _s_indices); +#endif vbuff = _vbuff = _device.VertexBuffer(_vertices); ibuff = _ibuff = _device.IndexBuffer(_indices); diff --git a/3D/Shader.h b/3D/Shader.h index 1b3b09938..c586092de 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -46,7 +46,13 @@ struct MVPBuffer { DXVector3 lightdir; private: - char _unused[4]; + float _unused1; + + public: + DXColor mat_color; + + private: + // char _unused2[1]; }; // Vertex layout used for Vertex Shaders. @@ -85,8 +91,10 @@ class Shader : public Dynamic { void SetCBuffer(const X& data) { // Unfortunately we can't make this method virtual. if (dynamic_cast(&this) != NULL) { - // MT5's DirectX. +// MT5's DirectX. +#ifdef __debug__ Print("Setting CBuffer data for MT5"); +#endif ((MTDXShader*)&this).SetCBuffer(data); } else { Alert("Unsupported cbuffer device target"); diff --git a/3D/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl index b6710ff2d..beaeada19 100644 --- a/3D/Shaders/cube_ps.hlsl +++ b/3D/Shaders/cube_ps.hlsl @@ -7,6 +7,5 @@ struct INPUT { float4 main(INPUT input) : SV_TARGET { float4 ambient = {0.0, 0.2, 0.4, 1.0}; - return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); + return ambient + input.color * saturate(dot(input.lightdir, input.normal)); } -//+------------------------------------------------------------------+ diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl index a1ea75989..a4928a1d7 100644 --- a/3D/Shaders/cube_vs.hlsl +++ b/3D/Shaders/cube_vs.hlsl @@ -3,6 +3,7 @@ cbuffer MVP : register(b0) { matrix view; matrix projection; float3 lightdir; + float4 mat_color; }; struct INPUT { @@ -21,15 +22,12 @@ struct OUTPUT { OUTPUT main(INPUT input) { OUTPUT output; - input.position.w = 1.0f; + matrix mvp = mul(mul(world, view), projection); + output.position = mul(input.position, mvp); - matrix mvp = mul(mul(projection, view), world); - - output.position = mul(mvp, input.position); - - output.normal = normalize(mul(world, input.normal)); + output.normal = normalize(mul(input.normal, world)); output.lightdir = lightdir; - output.color = input.color; + output.color = input.color * mat_color; return output; } \ No newline at end of file diff --git a/3D/TSR.h b/3D/TSR.h index 09247b830..d56f8ecc3 100644 --- a/3D/TSR.h +++ b/3D/TSR.h @@ -27,7 +27,8 @@ #include "Math.h" -struct TSR { +class TSR { + public: DXVector3 translation; DXVector3 scale; DXVector3 rotation; diff --git a/3D/Vertex.h b/3D/Vertex.h index 83ccfe50f..8466fa312 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -6,13 +6,13 @@ struct Vertex { DXVector3 Position; DXVector3 Normal; - DXVector Color; + DXColor Color; Vertex() { - Color.x = 1.0f; - Color.y = 1.0f; - Color.z = 1.0f; - Color.w = 1.0f; + Color.r = 1.0f; + Color.g = 1.0f; + Color.b = 1.0f; + Color.a = 1.0f; } static const ShaderVertexLayout Layout[3]; diff --git a/Refs.struct.h b/Refs.struct.h index 784cd4fd2..232dc1732 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -107,6 +107,10 @@ struct Ref { ptr_object.ptr_ref_counter = NULL; ptr_object = NULL; +#ifdef __debug__ + Print("Refs: Deleting object ", ptr_to_delete); +#endif + delete ptr_to_delete; } diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index 6cdb51f59..9d94f4069 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,14 +1,12 @@ -struct INPUT -{ +struct INPUT { float4 position : SV_POSITION; float4 normal : TEXCOORD0; float3 lightdir : TEXCOORD1; float4 color : COLOR; }; -float4 main(INPUT input) : SV_TARGET -{ - float4 ambient = {0.0, 0.2, 0.4, 1.0}; - return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); +float4 main(INPUT input) : SV_TARGET { + float4 ambient = {0.0, 0.2, 0.4, 1.0}; + return ambient + input.color * saturate(dot(input.lightdir, input.normal)); } //+------------------------------------------------------------------+ diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index a58290c6f..5ed5a0f9b 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -26,6 +26,8 @@ #ifdef __MQL5__ +//#define __debug__ + // Resources. #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; @@ -50,8 +52,6 @@ BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { return Chart::GetOHL int OnInit() { return OnStart(); } -struct PSCBuffer : MVPBuffer {}; - /** * Implements OnStart(). */ @@ -67,7 +67,7 @@ int OnStart() { Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); Ref _shader_p = gfx.PixelShader(ShaderSourcePS); - Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); + Ref> _mesh = new Cube(1.0f, 1.0f, 1.0f); _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); @@ -75,8 +75,8 @@ int OnStart() { unsigned int _rand_color = rand() * 1256; - gfx.SetCameraOrtho3D(); - gfx.SetLightDirection(0, 0, -1.0f); + gfx.SetCameraOrtho3D(0.0f, 0.0f, 20.0f); + gfx.SetLightDirection(0.0f, 0.0f, -1.0f); while (!IsStopped()) { if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { @@ -86,24 +86,15 @@ int OnStart() { gfx.Begin(0x777255EE); static float x = 0; - x += 0.04f; + x += 0.0f; TSR tsr; - tsr.rotation.x = x; + tsr.rotation.y = sin(x) / 3; + tsr.rotation.x = sin(x / 4) / 3; gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr()); - gfx.PopTransform(); - - tsr.translation.x = 50; - tsr.translation.y = -180; - tsr.rotation.z = 1.9f; - - gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr()); - gfx.PopTransform(); - _chart.Ptr().Render(gfx); + gfx.PopTransform(); gfx.End(); From 989836a941cc04c3ee5657649ae64b2c845a3886 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 13 May 2021 22:31:18 +0200 Subject: [PATCH 09/97] WIP. Added candles chart rendering and price cache. --- 3D/Chart3D.h | 36 +++++++++++++++++++++++++++++------- 3D/Chart3DCandles.h | 33 ++++++++++++++++++++++++++++----- 3D/Device.h | 13 ++++--------- 3D/Frontends/MT5Frontend.h | 2 +- 3D/Material.h | 18 ++++++++++++++++++ 3D/Shaders/cube_ps.hlsl | 10 ++++++++-- 3D/Shaders/cube_vs.hlsl | 2 +- 3D/TSR.h | 2 +- tests/3DTest.mq5 | 37 +++++++++++++++++++++++++++++-------- 9 files changed, 119 insertions(+), 34 deletions(-) create mode 100644 3D/Material.h diff --git a/3D/Chart3D.h b/3D/Chart3D.h index e8568a482..fdafdf0ac 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -116,20 +116,42 @@ class Chart3D : public Dynamic { BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } - int GetBarsVisibleShiftStart() { return 20; } + int GetBarsVisibleShiftStart() { return 80; } int GetBarsVisibleShiftEnd() { return 0; } + float GetMinBarsPrice() { + float _min = 100.0f; + for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { + BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); + if (_ohlc.GetMinOC() < _min) { + _min = _ohlc.GetMinOC(); + } + } + return _min; + } + + float GetMaxBarsPrice() { + float _max = -100.0f; + for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { + BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); + if (_ohlc.GetMaxOC() > _max) { + _max = _ohlc.GetMaxOC(); + } + } + return _max; + } + int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; } - float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.1f / 2.0f + 1.1f * _shift; } + float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.25f / 2.0f + 1.25f * _shift; } float GetPriceScale(float price) { - float _scale_y = 1.0f; - float _price_min = 1.194f; - float _price_max = 1.20f; - // Print(price); - return _scale_y / (_price_max - _price_min) * (price - _price_min); + float _scale_y = 20.0f; + float _price_min = GetMinBarsPrice(); + float _price_max = GetMaxBarsPrice(); + float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y; + return _result; } /** diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index baf4b45f6..c230003c1 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -38,6 +38,7 @@ class Chart3D; class Chart3DCandles : public Chart3DType { Ref> cube1; Ref> cube2; + Ref> cube3; public: /** @@ -45,7 +46,8 @@ class Chart3DCandles : public Chart3DType { */ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { cube1 = new Cube(1.0f, 1.0f, 1.0f); - cube2 = new Cube(0.15f, 0.15f, 0.15f); + cube2 = new Cube(0.15f, 1.0f, 0.15f); + cube3 = new Cube(1.0f, 0.15f, 0.15f); } /** @@ -57,15 +59,36 @@ class Chart3DCandles : public Chart3DType { for (int _shift = chart3d.GetBarsVisibleShiftStart(); _shift != chart3d.GetBarsVisibleShiftEnd(); --_shift) { BarOHLC _ohlc = chart3d.GetPrice(PERIOD_CURRENT, _shift); + float _height = chart3d.GetPriceScale(_ohlc.GetMaxOC()) - chart3d.GetPriceScale(_ohlc.GetMinOC()); + float higher = _ohlc.IsBear(); + cube1.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); - cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.open); - cube1.Ptr().GetMaterial().SetColor(0xFF0000); + cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetMinOC()) + _height / 2; + cube1.Ptr().GetTSR().scale.y = _height; + + //Print(cube1.Ptr().GetTSR().translation.y); + + cube1.Ptr().GetMaterial().SetColor(higher ? 0x00FF00 : 0xFF0000); _device.Render(cube1.Ptr()); cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); - cube2.Ptr().GetTSR().scale.y = 10.0f; - cube2.Ptr().GetMaterial().SetColor(0xFF0000); + float _line_height = chart3d.GetPriceScale(_ohlc.GetHigh()) - chart3d.GetPriceScale(_ohlc.GetLow()); + cube2.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetLow()) + _line_height / 2; + cube2.Ptr().GetTSR().scale.y = _line_height; + cube2.Ptr().GetMaterial().SetColor(0x8888888); _device.Render(cube2.Ptr()); } + + // Rendering price lines. + if (true) + for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 5.55f) { + float _y = chart3d.GetPriceScale(_s); + + cube3.Ptr().GetTSR().translation.y = _y; + cube3.Ptr().GetTSR().scale.x = 200.0f; + + cube3.Ptr().GetMaterial().SetColor(0xFFFFFFFF); + _device.Render(cube3.Ptr()); + } } }; \ No newline at end of file diff --git a/3D/Device.h b/3D/Device.h index 5fd811132..c492f6df2 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -194,9 +194,11 @@ class Device : public Dynamic { IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); - PushTransform(_mesh.GetTSR()); SetMaterial(_mesh.GetMaterial()); + + PushTransform(_mesh.GetTSR()); + SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS()); SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS()); @@ -229,14 +231,7 @@ class Device : public Dynamic { int Height() { return frontend.Ptr().Height(); } void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { - DXMatrixOrthoLH(mtx_view, 1.0f, 1.0f / Width() * Height(), -10000, 10000); - mtx_view.m[3][3] = _pos_z; - DXMatrix _translate; - DXMatrix _scale; - DXMatrixTranslation(_translate, _pos_x, _pos_y, 0.0f); - DXMatrixTranslation(_scale, 1.0f / _pos_z, 1.0f / _pos_z, 0.0f); - // DXMatrixMultiply(mtx_view, _translate, mtx_view); - // DXMatrixMultiply(mtx_view, mtx_view, _scale); + DXMatrixOrthoLH(mtx_projection, 1.0f * _pos_z, 1.0f / Width() * Height() * _pos_z, -10000, 10000); } DXMatrix GetWorldMatrix() { return mtx_world; } diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 6c88f1347..d431ec171 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -142,7 +142,7 @@ class MT5Frontend : public Frontend { Print("ResourceCreate: LastError: ", GetLastError()); #endif ChartRedraw(); - Sleep(5); + Sleep(1); } /** diff --git a/3D/Material.h b/3D/Material.h new file mode 100644 index 000000000..1cb05704b --- /dev/null +++ b/3D/Material.h @@ -0,0 +1,18 @@ +#include "Math.h" + +/** + * Generic vertex to be used by meshes. + */ +class Material { + public: + DXColor Color; + + Material(unsigned int _color = 0xFFFFFFFF) { Color = DXColor(_color); } + + Material(const Material& _r) { Color = _r.Color; } + + Material* SetColor(unsigned int _color) { + Color = DXColor(_color); + return &this; + } +}; diff --git a/3D/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl index beaeada19..6218a4748 100644 --- a/3D/Shaders/cube_ps.hlsl +++ b/3D/Shaders/cube_ps.hlsl @@ -6,6 +6,12 @@ struct INPUT { }; float4 main(INPUT input) : SV_TARGET { - float4 ambient = {0.0, 0.2, 0.4, 1.0}; - return ambient + input.color * saturate(dot(input.lightdir, input.normal)); + float4 ambient = {0.0, 0.1, 0.3, 1.0}; + input.color.a = 1.0f; + float ambient_contribution = 0.1f; + float diffuse_contribution = 0.6f; + float lighting_contribution = 1.0f - diffuse_contribution - ambient_contribution; + + return ambient_contribution * ambient + diffuse_contribution * input.color + + lighting_contribution * input.color * saturate(dot(input.lightdir, input.normal)); } diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl index a4928a1d7..c28c1b513 100644 --- a/3D/Shaders/cube_vs.hlsl +++ b/3D/Shaders/cube_vs.hlsl @@ -22,7 +22,7 @@ struct OUTPUT { OUTPUT main(INPUT input) { OUTPUT output; - matrix mvp = mul(mul(world, view), projection); + matrix mvp = mul(mul(view, world), projection); output.position = mul(input.position, mvp); output.normal = normalize(mul(input.normal, world)); diff --git a/3D/TSR.h b/3D/TSR.h index d56f8ecc3..88b586693 100644 --- a/3D/TSR.h +++ b/3D/TSR.h @@ -54,8 +54,8 @@ class TSR { DXMatrixIdentity(_mtx_result); DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_1); DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_2); - DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation); DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_scale); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation); return _mtx_result; } diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 5ed5a0f9b..8809ab565 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -35,6 +35,10 @@ //#define Print if (false) Print // Includes. +#include "../Serializer.mqh" +#include "../Test.mqh" +#include "../BufferStruct.mqh" +#include "../Chart.mqh" #include "../3D/Chart3D.h" #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" @@ -42,13 +46,30 @@ #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../3D/Frontends/MT5Frontend.h" -#include "../Chart.mqh" -#include "../Serializer.mqh" -#include "../Test.mqh" // int OnStart() { return OnInit(); } -BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { return Chart::GetOHLC(_tf, _shift); } +BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { + static Chart _chart(_tf); + static BufferStruct idata; + + long _bar_time = _chart.GetBarTime(_shift); + unsigned int _position; + IndicatorDataEntry _entry(4); + if (idata.KeyExists(_bar_time, _position)) { + _entry = idata.GetByPos(_position); + } else { + _entry.timestamp = _chart.GetBarTime(_tf, _shift); + _entry.values[0] = (float)_chart.GetOpen(_tf, _shift); + _entry.values[1] = (float)_chart.GetHigh(_tf, _shift); + _entry.values[2] = (float)_chart.GetLow(_tf, _shift); + _entry.values[3] = (float)_chart.GetClose(_tf, _shift); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); + idata.Add(_entry, _bar_time); + } + + return BarOHLC(_entry.GetValue(0), _entry.GetValue(1), _entry.GetValue(2), _entry.GetValue(3)); +} int OnInit() { return OnStart(); } @@ -75,7 +96,7 @@ int OnStart() { unsigned int _rand_color = rand() * 1256; - gfx.SetCameraOrtho3D(0.0f, 0.0f, 20.0f); + gfx.SetCameraOrtho3D(0.0f, 0.0f, 80.0f); gfx.SetLightDirection(0.0f, 0.0f, -1.0f); while (!IsStopped()) { @@ -86,11 +107,11 @@ int OnStart() { gfx.Begin(0x777255EE); static float x = 0; - x += 0.0f; + x += 0.15f; TSR tsr; - tsr.rotation.y = sin(x) / 3; - tsr.rotation.x = sin(x / 4) / 3; + tsr.rotation.y = sin(x) / 4; + tsr.rotation.x = sin(x / 2) * 0.3f; gfx.PushTransform(tsr); _chart.Ptr().Render(gfx); From e0fc1355c07b703a824318e81762eba0622ce489 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 15 May 2021 16:19:30 +0200 Subject: [PATCH 10/97] WIP. --- 3D/Chart3D.h | 49 +++++++++++++++++++++++++++------------------ 3D/Chart3DCandles.h | 13 ++++++------ Chart.struct.h | 7 ++++--- Util.h | 9 +++++++++ tests/3DTest.mq5 | 19 +++++++++--------- 5 files changed, 59 insertions(+), 38 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index fdafdf0ac..d2e182c85 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -29,6 +29,7 @@ #include "../Refs.mqh" #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" +#include "../Indicators/Indi_MA.mqh" #include "Chart3DCandles.h" #include "Chart3DType.h" #include "Cube.h" @@ -114,43 +115,53 @@ class Chart3D : public Dynamic { return renderers[type].Ptr(); } + /** + * Returns given bar's OHLC. + */ BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } + /** + * Return first shift that are visible on the screen. Values is away from 0. + */ int GetBarsVisibleShiftStart() { return 80; } + /** + * Return last shift that are visible on the screen. Value is closer to 0. + */ int GetBarsVisibleShiftEnd() { return 0; } + /** + * Returns lowest price of bars on the screen. + */ float GetMinBarsPrice() { - float _min = 100.0f; - for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { - BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); - if (_ohlc.GetMinOC() < _min) { - _min = _ohlc.GetMinOC(); - } - } - return _min; + return ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } + /** + * Returns highest price of bars on the screen. + */ float GetMaxBarsPrice() { - float _max = -100.0f; - for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { - BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); - if (_ohlc.GetMaxOC() > _max) { - _max = _ohlc.GetMaxOC(); - } - } - return _max; + return ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } + /** + * Returns number of bars that are visible on te screen. + */ int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; } - float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.25f / 2.0f + 1.25f * _shift; } + /** + * Returns absolute x coordinate of bar on the screen. Must not be affected by camera's x offset. + */ + float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.35f / 2.0f + 1.35f * _shift; } + /** + * Returns y coordinate of price on the screen. Takes into consideration zoom and min/max prices on the screen. + */ float GetPriceScale(float price) { - float _scale_y = 20.0f; + float _scale_y = 40.0f; float _price_min = GetMinBarsPrice(); float _price_max = GetMaxBarsPrice(); - float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y; + float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y - (_scale_y / 2); return _result; } diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index c230003c1..3532407ce 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -46,8 +46,8 @@ class Chart3DCandles : public Chart3DType { */ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { cube1 = new Cube(1.0f, 1.0f, 1.0f); - cube2 = new Cube(0.15f, 1.0f, 0.15f); - cube3 = new Cube(1.0f, 0.15f, 0.15f); + cube2 = new Cube(0.10f, 1.0f, 0.10f); + cube3 = new Cube(1.0f, 0.075f, 0.075f); } /** @@ -68,26 +68,25 @@ class Chart3DCandles : public Chart3DType { //Print(cube1.Ptr().GetTSR().translation.y); - cube1.Ptr().GetMaterial().SetColor(higher ? 0x00FF00 : 0xFF0000); + cube1.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube1.Ptr()); cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); float _line_height = chart3d.GetPriceScale(_ohlc.GetHigh()) - chart3d.GetPriceScale(_ohlc.GetLow()); cube2.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetLow()) + _line_height / 2; cube2.Ptr().GetTSR().scale.y = _line_height; - cube2.Ptr().GetMaterial().SetColor(0x8888888); + cube2.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube2.Ptr()); } // Rendering price lines. - if (true) - for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 5.55f) { + for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 0.0001f) { float _y = chart3d.GetPriceScale(_s); cube3.Ptr().GetTSR().translation.y = _y; cube3.Ptr().GetTSR().scale.x = 200.0f; - cube3.Ptr().GetMaterial().SetColor(0xFFFFFFFF); + cube3.Ptr().GetMaterial().SetColor(0x333333); _device.Render(cube3.Ptr()); } } diff --git a/Chart.struct.h b/Chart.struct.h index e17f8408e..4e729db66 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -38,6 +38,7 @@ class Class; #include "Chart.define.h" #include "Chart.enum.h" #include "Chart.struct.tf.h" +#include "Util.h" #include "Serializer.mqh" #include "Terminal.define.h" @@ -352,15 +353,15 @@ struct ChartStatic { case MODE_VOLUME: ArraySetAsSeries(arr_l, true); CopyTickVolume(_symbol, _tf, _start, _count, arr_l); - return (ArrayMinimum(arr_l, 0, _count) + _start); + return ArrayMinimum(arr_l, 0, _count) + _start; case MODE_TIME: ArraySetAsSeries(arr_dt, true); CopyTime(_symbol, _tf, _start, _count, arr_dt); - return (ArrayMinimum(arr_dt, 0, _count) + _start); + return ArrayMinimum(arr_dt, 0, _count) + _start; default: break; } - return (ArrayMinimum(arr_d, 0, _count) + _start); + return ArrayMinimum(arr_d, 0, _count) + _start; #endif } diff --git a/Util.h b/Util.h index 06676caf0..3933d9d46 100644 --- a/Util.h +++ b/Util.h @@ -53,4 +53,13 @@ class Util { ::ArrayResize(_array, ArraySize(_array) - 1); return _result; } + + template + static T Print(T& _array[]) { + string _result; + for (int i = 0; i < ArraySize(_array); ++i) { + _result += IntegerToString(i) + ": " + (string)_array[i]; + } + return _result; + } }; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 8809ab565..a9d1d07af 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -49,8 +49,9 @@ // int OnStart() { return OnInit(); } + BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { - static Chart _chart(_tf); + static Chart _chart(); static BufferStruct idata; long _bar_time = _chart.GetBarTime(_shift); @@ -59,11 +60,11 @@ BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { - _entry.timestamp = _chart.GetBarTime(_tf, _shift); - _entry.values[0] = (float)_chart.GetOpen(_tf, _shift); - _entry.values[1] = (float)_chart.GetHigh(_tf, _shift); - _entry.values[2] = (float)_chart.GetLow(_tf, _shift); - _entry.values[3] = (float)_chart.GetClose(_tf, _shift); + _entry.timestamp = _chart.GetBarTime(_shift); + _entry.values[0] = (float)_chart.GetOpen(_shift); + _entry.values[1] = (float)_chart.GetHigh(_shift); + _entry.values[2] = (float)_chart.GetLow(_shift); + _entry.values[3] = (float)_chart.GetClose(_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); idata.Add(_entry, _bar_time); } @@ -96,7 +97,7 @@ int OnStart() { unsigned int _rand_color = rand() * 1256; - gfx.SetCameraOrtho3D(0.0f, 0.0f, 80.0f); + gfx.SetCameraOrtho3D(0.0f, 0.0f, 100.0f); gfx.SetLightDirection(0.0f, 0.0f, -1.0f); while (!IsStopped()) { @@ -104,10 +105,10 @@ int OnStart() { break; } - gfx.Begin(0x777255EE); + gfx.Begin(0x00FFFFFF); static float x = 0; - x += 0.15f; + x += 0.025f; TSR tsr; tsr.rotation.y = sin(x) / 4; From cf408631770d5c8ab1d4da50e7f6f1f11e52e4ea Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 19 May 2021 22:40:54 +0200 Subject: [PATCH 11/97] WIP. Somehow chart events doesn't work. --- 3D/Chart3D.h | 38 +++++++++-- 3D/Chart3DCandles.h | 13 +++- 3D/Chart3DType.h | 4 ++ 3D/Device.h | 36 ++++++++++- 3D/Frontend.h | 40 ++++++++++++ 3D/Frontends/MT5Frontend.h | 16 +++++ 3D/Interface.h | 129 +++++++++++++++++++++++++++++++++++++ Instances.h | 51 +++++++++++++++ Util.h | 16 ++++- tests/3DTest.mq5 | 6 +- 10 files changed, 338 insertions(+), 11 deletions(-) create mode 100644 3D/Interface.h create mode 100644 Instances.h diff --git a/3D/Chart3D.h b/3D/Chart3D.h index d2e182c85..a0bf9f9f7 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -30,10 +30,12 @@ #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" #include "../Indicators/Indi_MA.mqh" +#include "../Instances.h" #include "Chart3DCandles.h" #include "Chart3DType.h" #include "Cube.h" #include "Device.h" +#include "Interface.h" // Resources. #resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; @@ -48,6 +50,13 @@ enum ENUM_CHART3D_TYPE { CHART3D_TYPE_LINES, }; +class Chart3D; + +void chart3d_interface_listener(InterfaceEvent& _event, void* _target) { + Chart3D* chart3d = (Chart3D*)_target; + chart3d.OnInterfaceEvent(_event); +} + /** * 3D chart renderer. */ @@ -70,22 +79,41 @@ class Chart3D : public Dynamic { // Shaders. Ref shader_vs; Ref shader_ps; + + Chart3DType* current_renderer; + + Instances instances; public: /** * Constructor. */ - Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) { + Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) : instances(&this) { price_fetcher = _price_fetcher; type = _type; offset.x = offset.y = 0.0f; offset.z = 25.0f; initialized = false; + Interface::AddListener(chart3d_interface_listener, &this); } - + + void OnInterfaceEvent(InterfaceEvent& _event) { + if (GetCurrentRenderer() == NULL) { + return; + } + + Device* _gfx = GetCurrentRenderer().GetDevice(); + + _gfx.DrawText(10, 10, "Event!"); + } + Shader* GetShaderVS() { return shader_vs.Ptr(); } Shader* GetShaderPS() { return shader_ps.Ptr(); } + + Chart3DType* GetCurrentRenderer() { + return current_renderer; + } Chart3DType* GetRenderer(Device* _device) { if (!initialized) { @@ -111,6 +139,8 @@ class Chart3D : public Dynamic { return NULL; } } + + current_renderer = renderers[type].Ptr(); return renderers[type].Ptr(); } @@ -134,14 +164,14 @@ class Chart3D : public Dynamic { * Returns lowest price of bars on the screen. */ float GetMinBarsPrice() { - return ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + return (float)ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } /** * Returns highest price of bars on the screen. */ float GetMaxBarsPrice() { - return ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + return (float)ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } /** diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 3532407ce..fbab65553 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -79,13 +79,22 @@ class Chart3DCandles : public Chart3DType { _device.Render(cube2.Ptr()); } + int _digits = (int)MarketInfo(Symbol(), MODE_DIGITS); + float _pip_pow = (float)MathPow(10, _digits); + float _pip_size = 1.0f / (float)MathPow(10, _digits); + float _pip_size_m1 = 1.0f / (float)MathPow(10, _digits - 1); + float _start = float(int(chart3d.GetMinBarsPrice() * _pip_pow) * _pip_size); + float _end = float(int(chart3d.GetMaxBarsPrice() * _pip_pow) * _pip_size); + // Rendering price lines. - for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 0.0001f) { - float _y = chart3d.GetPriceScale(_s); + for (double _s = _start; _s < _end + _pip_size_m1; _s += _pip_size * 10) { + float _y = chart3d.GetPriceScale((float)_s); cube3.Ptr().GetTSR().translation.y = _y; cube3.Ptr().GetTSR().scale.x = 200.0f; + _device.DrawText(5, _y, StringFormat("%." + IntegerToString(_digits) + "f", _s), 0x90FFFFFF, TA_LEFT | TA_VCENTER, GFX_DRAW_TEXT_FLAG_2D_COORD_X); + cube3.Ptr().GetMaterial().SetColor(0x333333); _device.Render(cube3.Ptr()); } diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h index d96de2463..122444dbd 100644 --- a/3D/Chart3DType.h +++ b/3D/Chart3DType.h @@ -44,6 +44,10 @@ class Chart3DType : public Dynamic { * Constructor. */ Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {} + + Device* GetDevice() { + return device; + } /** * Renders chart. diff --git a/3D/Device.h b/3D/Device.h index c492f6df2..d449565a5 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -35,6 +35,12 @@ #include "Shader.h" #include "VertexBuffer.h" +enum GFX_DRAW_TEXT_FLAGS { + GFX_DRAW_TEXT_FLAG_NONE, + GFX_DRAW_TEXT_FLAG_2D_COORD_X, + GFX_DRAW_TEXT_FLAG_2D_COORD_Y +}; + enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; /** @@ -90,6 +96,7 @@ class Device : public Dynamic { Device* End() { RenderEnd(); frontend.Ptr().RenderEnd(context); + frontend.Ptr().ProcessDrawText(); return &this; } @@ -254,6 +261,33 @@ class Device : public Dynamic { lightdir.z = z; } + /** + * Enqueues text to be drawn directly into the pixel buffer. Queue will be processed in the Device::End() method. + */ + void DrawText(float _x, float _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0, unsigned int _flags = 0) { + DViewport _viewport; + _viewport.x = 0; + _viewport.y = 0; + _viewport.width = frontend.Ptr().Width(); + _viewport.height = frontend.Ptr().Height(); + _viewport.minz = -10000.0f; + _viewport.maxz = 10000.0f; + + DXVector3 _vec3_in(_x, _y, 0.0f); + DXVector3 _vec3_out; + DXVec3Project(_vec3_out, _vec3_in, _viewport, GetProjectionMatrix(), GetViewMatrix(), GetWorldMatrix()); + + if ((_flags & GFX_DRAW_TEXT_FLAG_2D_COORD_X) == GFX_DRAW_TEXT_FLAG_2D_COORD_X) { + _vec3_out.x = _x; + } + + if ((_flags & GFX_DRAW_TEXT_FLAG_2D_COORD_Y) == GFX_DRAW_TEXT_FLAG_2D_COORD_Y) { + _vec3_out.y = _y; + } + + frontend.Ptr().DrawText(_vec3_out.x, _vec3_out.y, _text, _color, _align); + } + protected: /** * Initializes graphics device. @@ -279,4 +313,4 @@ class Device : public Dynamic { * Clears color buffer. */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color) = NULL; -}; \ No newline at end of file +}; diff --git a/3D/Frontend.h b/3D/Frontend.h index 6edbec4bf..5757e7893 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -27,10 +27,22 @@ #include "../Refs.mqh" +struct DrawTextQueueItem { + float x; + float y; + string text; + unsigned int rgb; + unsigned int align; +}; + /** * Represents visual target (OS window/canvas for rendering). */ class Frontend : public Dynamic { + protected: + + DrawTextQueueItem draw_text_queue[]; + public: /** * Initializes canvas. @@ -71,4 +83,32 @@ class Frontend : public Dynamic { * Returns canvas' height. */ virtual int Height() = NULL; + + /** + * Enqueues text to be drawn directly into the pixel buffer. Queue will be processed in the Device::End() method. + */ + virtual void DrawText(float _x, float _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) { + DrawTextQueueItem _item; + _item.x = _x; + _item.y = _y; + _item.text = _text; + _item.rgb = _color; + _item.align = _align; + Util::ArrayPush(draw_text_queue, _item); + } + + void ProcessDrawText() { + for (int i = 0; i < ArraySize(draw_text_queue); ++i) { + DrawTextQueueItem _item = draw_text_queue[i]; + DrawTextNow((int)_item.x, (int)_item.y, _item.text, _item.rgb, _item.align); + } + ArrayResize(draw_text_queue, 0); + } + +protected: + + /** + * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. + */ + virtual void DrawTextNow(int _x, int _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) {} }; \ No newline at end of file diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index d431ec171..f57b70a9d 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -134,6 +134,7 @@ class MT5Frontend : public Frontend { Print("MT5Frontend: DXContextGetColors()"); #endif DXContextGetColors(context, image); + ProcessDrawText(); #ifdef __debug__ Print("DXContextGetColors: LastError: ", GetLastError()); #endif @@ -154,4 +155,19 @@ class MT5Frontend : public Frontend { * Returns canvas' height. */ virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } + + /** + * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. + */ + virtual void DrawTextNow(int _x, int _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) { + TextSetFont("Arial", -80, FW_EXTRABOLD, 0); + #ifdef __debug__ + Print("TextSetFont: LastError = ", GetLastError()); + #endif + + TextOut(_text, _x, _y, _align, image, Width(), Height(), _color, COLOR_FORMAT_ARGB_NORMALIZE); + #ifdef __debug__ + Print("TextOut: LastError = ", GetLastError()); + #endif + } }; \ No newline at end of file diff --git a/3D/Interface.h b/3D/Interface.h new file mode 100644 index 000000000..5bacb1d8b --- /dev/null +++ b/3D/Interface.h @@ -0,0 +1,129 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Chart events. + */ + +#include "../Util.h" + +enum ENUM_INTERFACE_EVENT { + INTERFACE_EVENT_NONE, + INTERFACE_EVENT_MOUSE_MOVE, + INTERFACE_EVENT_MOUSE_DOWN, + INTERFACE_EVENT_MOUSE_UP +}; + +struct InterfaceEvent { + ENUM_INTERFACE_EVENT type; + struct EventMouse { + int x; + int y; + datetime dt; + }; + + union EventData { + EventMouse mouse; + } data; +}; + + +void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { + datetime _dt; + double _mp; + int _window = 0; + InterfaceEvent _event; + + + if (id == CHART_EVENT_MOUSE_MOVE) { + Interface::mouse_pos_x = (int)lparam; + Interface::mouse_pos_y = (int)dparam; + ChartXYToTimePrice(0, Interface::mouse_pos_x, Interface::mouse_pos_y, _window, _dt, _mp); + _event.type = INTERFACE_EVENT_MOUSE_MOVE; + _event.data.mouse.x = Interface::mouse_pos_x; + _event.data.mouse.y = Interface::mouse_pos_y; + Interface::FireEvent(_event); + } +} + +typedef void (*InterfaceListener)(InterfaceEvent&, void*); + +class Interface +{ + public: + + struct Installation + { + InterfaceListener listener; + void* target; + }; + + static Installation installations[]; + + static bool mouse_was_down; + static int mouse_pos_x; + static int mouse_pos_y; + static bool initialized; + + static void AddListener(InterfaceListener _listener, void* _target) { + if (!initialized) { + ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); + ChartRedraw(); + initialized = true; + } + + for (int i = 0; i < ArraySize(installations); ++i) { + if (installations[i].listener == _listener) { + // Listener already added. + return; + } + } + + Installation _installation; + _installation.listener = _listener; + _installation.target = _target; + + Util::ArrayPush(installations, _installation); + } + + static void FireEvent(InterfaceEvent& _event) { + for (int i = 0; i < ArraySize(installations); ++i) { + Installation _installation = installations[i]; + _installation.listener(_event, _installation.target); + } + } + + static int GetMouseX() { + return mouse_pos_x; + } + + static int GetMouseY() { + return mouse_pos_y; + } +}; + +Interface::Installation Interface::installations[]; +bool Interface::mouse_was_down = false; +int Interface::mouse_pos_x = 0; +int Interface::mouse_pos_y = 0; +bool Interface::initialized = false; diff --git a/Instances.h b/Instances.h new file mode 100644 index 000000000..ed1c264d8 --- /dev/null +++ b/Instances.h @@ -0,0 +1,51 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Collects information about class instances. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +#include "Dict.mqh" +#include "Util.h" + +template +class Instances { +public: + + static T* instances[]; + Instances(T* _self) { + Util::ArrayPush(instances, _self); + } + + ~Instances() { + //Util::ArrayRemove(instances, &this); + } +}; + +template +T* Instances::instances[]; \ No newline at end of file diff --git a/Util.h b/Util.h index 3933d9d46..e03176268 100644 --- a/Util.h +++ b/Util.h @@ -38,7 +38,7 @@ class Util { * Pushes item into the native array and reserves space for further items by some fixed step. */ template - static int ArrayPush(T& _array[], const V& _value, int _resize_pool = 32) { + static int ArrayPush(T& _array[], V& _value, int _resize_pool = 32) { Util::ArrayResize(_array, ArraySize(_array) + 1, _resize_pool); _array[ArraySize(_array) - 1] = _value; return ArraySize(_array) - 1; @@ -62,4 +62,18 @@ class Util { } return _result; } + + /** + * Checks whether array has given value. + */ + template + static bool ArrayContains(T& _array[], const V& _value) { + for (int i = 0; i < ArraySize(_array); ++i) { + if (_array[i] == _value) { + return true; + } + } + + return false; + } }; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index a9d1d07af..5ba1014e7 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -111,9 +111,9 @@ int OnStart() { x += 0.025f; TSR tsr; - tsr.rotation.y = sin(x) / 4; - tsr.rotation.x = sin(x / 2) * 0.3f; - + //tsr.rotation.y = (float)sin(x) / 4.0f; + tsr.rotation.x = (float)sin(x / 2); + gfx.PushTransform(tsr); _chart.Ptr().Render(gfx); gfx.PopTransform(); From 9a3da48db1ba96632c7d557fa6b03f7069012152 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 16 Apr 2021 18:18:50 +0200 Subject: [PATCH 12/97] WIP. 3D visualization for MT5. --- 3D/Device.h | 88 ++++++++ 3D/Devices/MTDX/MTDXDevice.h | 81 +++++++ 3D/Devices/MTDX/MTDXIndexBuffer.h | 13 ++ 3D/Devices/MTDX/MTDXShader.h | 25 +++ 3D/Devices/MTDX/MTDXVertexBuffer.h | 12 ++ 3D/Frontend.h | 37 ++++ 3D/Frontends/MT5Frontend.h | 19 ++ 3D/IndexBuffer.h | 26 +++ 3D/Shader.h | 38 ++++ 3D/Vertex.h | 11 + 3D/VertexBuffer.h | 21 ++ tests/3D/Shaders/pixel.hlsl | 328 +++++++++++++++++++++++++++++ tests/3D/Shaders/vertex.hlsl | 18 ++ tests/3DTest.mq5 | 72 +++++++ 14 files changed, 789 insertions(+) create mode 100644 3D/Device.h create mode 100644 3D/Devices/MTDX/MTDXDevice.h create mode 100644 3D/Devices/MTDX/MTDXIndexBuffer.h create mode 100644 3D/Devices/MTDX/MTDXShader.h create mode 100644 3D/Devices/MTDX/MTDXVertexBuffer.h create mode 100644 3D/Frontend.h create mode 100644 3D/Frontends/MT5Frontend.h create mode 100644 3D/IndexBuffer.h create mode 100644 3D/Shader.h create mode 100644 3D/Vertex.h create mode 100644 3D/VertexBuffer.h create mode 100644 tests/3D/Shaders/pixel.hlsl create mode 100644 tests/3D/Shaders/vertex.hlsl create mode 100644 tests/3DTest.mq5 diff --git a/3D/Device.h b/3D/Device.h new file mode 100644 index 000000000..7c3925829 --- /dev/null +++ b/3D/Device.h @@ -0,0 +1,88 @@ +#include "../Refs.mqh" +#include "Frontend.h" +#include "IndexBuffer.h" +#include "Shader.h" +#include "VertexBuffer.h" + +enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; + +/** + * Graphics device. + */ +class Device : public Dynamic { + public: + bool Start(Frontend* _frontend) { return Init(_frontend); } + + Device* Begin() { + Clear(0x000000); + RenderBegin(); + return &this; + } + + Device* End() { + RenderEnd(); + return &this; + } + + Device* Stop() { + Deinit(); + return &this; + } + + Device* Clear(unsigned int _color = 0xFF000000) { + ClearBuffer(CLEAR_BUFFER_TYPE_COLOR, _color); + return &this; + } + + Device* ClearDepth() { + ClearBuffer(CLEAR_BUFFER_TYPE_DEPTH, 0); + return &this; + } + + /** + * Creates index buffer to be used by current graphics device. + */ + virtual IndexBuffer* IndexBuffer() = NULL; + + /** + * Creates vertex shader to be used by current graphics device. + */ + virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], + string _entry_point = "main") = NULL; + + /** + * Creates pixel shader to be used by current graphics device. + */ + virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + + /** + * Creates vertex buffer to be used by current graphics device. + */ + virtual VertexBuffer* VertexBuffer() = NULL; + + protected: + /** + * Initializes graphics device. + */ + virtual bool Init(Frontend*) = NULL; + + /** + * Deinitializes graphics device. + */ + virtual bool Deinit() = NULL; + + /** + * Starts rendering loop. + */ + virtual bool RenderBegin() = NULL; + + /** + * Ends rendering loop. + */ + virtual bool RenderEnd() = NULL; + + /** + * Clears color buffer. + */ + virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color) = NULL; +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h new file mode 100644 index 000000000..6094184f1 --- /dev/null +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -0,0 +1,81 @@ +#include "../../Device.h" + +class MTDXDevice : public Device { + protected: + int context; + + public: + /** + * Initializes graphics device. + */ + bool Init(Frontend* _frontend) { + context = DXContextCreate(_frontend.Width(), _frontend.Height()); + + return true; + } + + /** + * Deinitializes graphics device. + */ + bool Deinit() { return true; } + + /** + * Starts rendering loop. + */ + virtual bool RenderBegin() { return true; } + + /** + * Ends rendering loop. + */ + virtual bool RenderEnd() { return true; } + + /** + * Returns DX context's id. + */ + int Context() { return context; } + + /** + * Clears color buffer. + */ + /** + * Clears color buffer. + */ + virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color = 0x000000) { + if (_type == CLEAR_BUFFER_TYPE_COLOR) { + DXVector _dx_color; + _dx_color.x = 1; + DXContextClearColors(context, _dx_color); + } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { + DXContextClearDepth(context); + } + } + + /** + * Creates index buffer to be used by current graphics device. + */ + IndexBuffer* IndexBuffer() { return NULL; } + + /** + * Creates vertex shader to be used by current graphics device. + */ + virtual Shader* VertexShader(string _source_code, const ShaderVertexLayout& _layout[], string _entry_point = "main") { + MTDXShader* _shader = new MTDXShader(&this); + _shader.Create(SHADER_TYPE_VS, _source_code, _entry_point); + _shader.SetDataLayout(_layout); + return _shader; + } + + /** + * Creates pixel shader to be used by current graphics device. + */ + virtual Shader* PixelShader(string _source_code, string _entry_point = "main") { + MTDXShader* _shader = new MTDXShader(&this); + _shader.Create(SHADER_TYPE_PS, _source_code, _entry_point); + return _shader; + } + + /** + * Creates vertex buffer to be used by current graphics device. + */ + VertexBuffer* VertexBuffer() { return NULL; } +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h new file mode 100644 index 000000000..53109e770 --- /dev/null +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -0,0 +1,13 @@ +#include "../../IndexBuffer.h" + +class MTDXIndexBuffer : public IndexBuffer { + MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} + + /** + * Creates index buffer. + */ + virtual bool Create(void*& _data[]) { + // DXBufferCreate(((MTDXDevice*)Device()).Context(), DX_BUFFER_INDEX, &_data); + return true; + } +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h new file mode 100644 index 000000000..ccab5aae3 --- /dev/null +++ b/3D/Devices/MTDX/MTDXShader.h @@ -0,0 +1,25 @@ +#include "../../Shader.h" + +class MTDXShader : public Shader { + int handle; + + public: + MTDXShader(Device *_device) : Shader(_device) {} + + bool Create(ENUM_SHADER_TYPE _type, string _source_code, string _entry_point = "main") { + string error_text; + + handle = DXShaderCreate(((MTDXDevice *)GetDevice()).Context(), + _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, + error_text); + + return true; + } + + /** + * Sets vertex/pixel data layout to be used by shader. + */ + virtual void SetDataLayout(const ShaderVertexLayout &_layout[]) { + // DXShaderSetLayout(handle, _layout); + } +}; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h new file mode 100644 index 000000000..d6fe42414 --- /dev/null +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -0,0 +1,12 @@ +#include "../../VertexBuffer.h" + +class MTDXVertexBuffer : public VertexBuffer { + public: + /** + * Creates vertex buffer. + */ + virtual bool Create(void*& _data[]) { + DXBufferCreate(((MTDXDevice*)GetDevice()).Context(), DX_BUFFER_VERTEX, _data); + return true; + } +}; \ No newline at end of file diff --git a/3D/Frontend.h b/3D/Frontend.h new file mode 100644 index 000000000..6415d7c00 --- /dev/null +++ b/3D/Frontend.h @@ -0,0 +1,37 @@ +#include "../Refs.mqh" + +/** + * Represents visual target (OS window/canvas for rendering). + */ +class Frontend : public Dynamic { + public: + /** + * Initializes canvas. + */ + bool Start() { return Init(); } + + /** + * Deinitializes canvas. + */ + bool End() { return Deinit(); } + + /** + * Initializes canvas. + */ + virtual bool Init() = NULL; + + /** + * Deinitializes canvas. + */ + virtual bool Deinit() = NULL; + + /** + * Returns canvas' width. + */ + virtual int Width() = NULL; + + /** + * Returns canvas' height. + */ + virtual int Height() = NULL; +}; \ No newline at end of file diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h new file mode 100644 index 000000000..5ff154f38 --- /dev/null +++ b/3D/Frontends/MT5Frontend.h @@ -0,0 +1,19 @@ +#include "../Frontend.h" + +/** + * MetaTrader 5 chart target. + */ +class MT5Frontend : public Frontend { + virtual bool Init() { + // Hiding 2D chart. + ChartSetInteger(0, CHART_SHOW, false); + ChartRedraw(); + return true; + } + + virtual bool Deinit() { return true; } + + virtual int Width() { return (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); } + + virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } +}; \ No newline at end of file diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h new file mode 100644 index 000000000..4279991f8 --- /dev/null +++ b/3D/IndexBuffer.h @@ -0,0 +1,26 @@ +#include "../Refs.mqh" + +class Device; + +/** + * Vertices' index buffer. + */ +class IndexBuffer : public Dynamic { + WeakRef device; + + public: + /** + * Constructor. + */ + IndexBuffer(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } + + /** + * Creates index buffer. + */ + virtual bool Create(void*& _data[]) = NULL; +}; \ No newline at end of file diff --git a/3D/Shader.h b/3D/Shader.h new file mode 100644 index 000000000..e013d54c0 --- /dev/null +++ b/3D/Shader.h @@ -0,0 +1,38 @@ +#include "../Refs.mqh" + +enum ENUM_SHADER_TYPE { + SHADER_TYPE_VS, + SHADER_TYPE_PS, +}; + +class Device; + +enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; + +struct ShaderVertexLayout { + string name; + unsigned int index; + ENUM_GFX_VAR_TYPE_FLOAT type; + unsigned int num_components; + bool clamped; + unsigned int stride; + unsigned int offset; +}; + +/** + * Unified vertex/pixel shader. + */ +class Shader : public Dynamic { + WeakRef device; + + public: + /** + * Constructor. + */ + Shader(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } +}; \ No newline at end of file diff --git a/3D/Vertex.h b/3D/Vertex.h new file mode 100644 index 000000000..6561fad32 --- /dev/null +++ b/3D/Vertex.h @@ -0,0 +1,11 @@ +#include "../Refs.mqh" + +struct Vertex { + struct Position { + float x, y, z; + } position; + + struct Color { + float r, g, b, a; + } color; +}; \ No newline at end of file diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h new file mode 100644 index 000000000..36ad0b53f --- /dev/null +++ b/3D/VertexBuffer.h @@ -0,0 +1,21 @@ +#include "../Refs.mqh" + +class VertexBuffer : public Dynamic { + WeakRef device; + + public: + /** + * Constructor. + */ + VertexBuffer(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } + + /** + * Creates index buffer. + */ + virtual bool Create(void*& _data[]) = NULL; +}; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl new file mode 100644 index 000000000..9445e5732 --- /dev/null +++ b/tests/3D/Shaders/pixel.hlsl @@ -0,0 +1,328 @@ +// Remnant X +// by David Hoskins. +// Thanks to boxplorer and the folks at 'Fractalforums.com' +// HD Video:- https://www.youtube.com/watch?v=BjkK9fLXXo0 +// https://www.shadertoy.com/view/4sjSW1 + +struct PSInput + { + float4 position : SV_POSITION; + }; + +cbuffer Input + { + float2 iResolution; + float iTime; + float iDummy; + }; + +#define PI 3.14159265f +#define SCALE 2.8 +#define MINRAD2 .25 +#define scale (float4(SCALE, SCALE, SCALE, abs(SCALE)) / minRad2) + +static const float minRad2 = clamp(MINRAD2, 1.0e-9, 1.0); +static const float absScalem1 = abs(SCALE - 1.0); +static const float AbsScaleRaisedTo1mIters = pow(abs(SCALE), float(1-10)); +static const float3 surfaceColour1 = float3(.8, .0, 0.); +static const float3 surfaceColour2 = float3(.4, .4, 0.5); +static const float3 surfaceColour3 = float3(.5, 0.3, 0.00); +static const float3 fogCol = float3(0.4, 0.4, 0.4); + +static const float3 sunDir=normalize(float3(0.35,0.1,0.3)); +static const float4 sunColour=float4(1.0,0.95,0.8,0.2); + + +float2 Rand(float2 p) + { + return(float2(frac(sin(dot(p,float2(12.9898,78.233)))*6.7416516),frac(sin(dot(p,float2(58.6542,22.6546)))*6.5465145))); + } + +float2 Texture(float2 p) + { + float2 p1=Rand(floor(p*256+float2(0,0))); + float2 p2=Rand(floor(p*256+float2(0,1))); + float2 p3=Rand(floor(p*256+float2(1,0))); + float2 p4=Rand(floor(p*256+float2(1,1))); + float2 f =frac(p*256); + + return lerp(lerp(p1,p2,f.y),lerp(p3,p4,f.y),f.x); + } + +//---------------------------------------------------------------------------------------- +float Noise(in float3 x) + { + float3 p=floor(x); + float3 f=frac(x); + f=f*f*(3.0-2.0*f); + + float2 uv=(p.xy+float2(37.0,17.0)*p.z)+f.xy; + float2 rg=Rand((uv+0.5)/256.0).yx;//texture(iChannel0,(uv+0.5)/256.0,-99.0).yx; + return lerp(rg.x,rg.y,f.z); + } + +//---------------------------------------------------------------------------------------- +float Map(float3 pos) + { + + float4 p=float4(pos,1); + float4 p0=p; // p.w is the distance estimate + + for(int i = 0; i < 9; i++) + { + p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; + + float r2=dot(p.xyz,p.xyz); + p*=clamp(max(minRad2/r2,minRad2),0.0,1.0); + + // scale, translate + p=p*scale+p0; + } + return ((length(p.xyz)-absScalem1)/p.w-AbsScaleRaisedTo1mIters); + } + +//---------------------------------------------------------------------------------------- +float3 Colour(float3 pos, float sphereR) + { + float3 p=pos; + float3 p0=p; + float trap=1.0; + + for(int i = 0; i < 6; i++) + { + p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; + float r2 = dot(p.xyz,p.xyz); + p*=clamp(max(minRad2/r2,minRad2), 0.0, 1.0); + + p=p*scale.xyz+p0.xyz; + trap=min(trap,r2); + } +// |c.x|: log final distance (fractional iteration count) +// |c.y|: spherical orbit trap at (0,0,0) + float2 c=clamp(float2(0.3333*log(dot(p,p))-1.0,sqrt(trap)),0.0, 1.0); + + float t=fmod(length(pos)-iTime*1.5,16.0); + float3 surfaceColour=lerp(surfaceColour1,float3(0.4,3.0,5.0),pow(smoothstep(0.0,0.3,t)*smoothstep(0.6,.3,t),10.0)); + return lerp(lerp(surfaceColour,surfaceColour2,c.y),surfaceColour3,c.x); + } + + +//---------------------------------------------------------------------------------------- +float3 GetNormal(float3 pos, float distance) + { + distance*=0.001+.0001; + float2 eps=float2(distance,0.0); + float3 nor=float3(Map(pos+eps.xyy) - Map(pos-eps.xyy), + Map(pos+eps.yxy) - Map(pos-eps.yxy), + Map(pos+eps.yyx) - Map(pos-eps.yyx)); + return normalize(nor); + } + +//---------------------------------------------------------------------------------------- +float GetSky(float3 pos) + { + pos*=0.02; + float2 t=0.5 *Texture(pos.xy*2.1) +0.5*Texture(pos.yz*2.3-(float2)0.53) +0.5*Texture(pos.zx*1.9+(float2)0.47)+ + 0.25 *Texture(pos.xy*4.7) +0.25*Texture(pos.yz*4.1+(float2)0.71) +0.25*Texture(pos.zx*4.3+(float2)0.59)+ + 0.125*Texture(pos.xy*8.7)+0.125*Texture(pos.yz*8.6-(float2)0.69)+0.125*Texture(pos.zx*8.3+(float2)0.95); + + return(pow(t.x*t.y,0.5)); + } + +//---------------------------------------------------------------------------------------- +float BinarySubdivision(in float3 rO, in float3 rD, float2 t) + { + float halfwayT; + + for(int i = 0; i < 6; i++) + { + + halfwayT=dot(t,float2(0.5,0.5)); + float d = Map(rO + halfwayT*rD); + //if (abs(d) < 0.001) break; + t=lerp(float2(t.x,halfwayT),float2(halfwayT,t.y),step(0.0005, d)); + } + + return halfwayT; + } + +//---------------------------------------------------------------------------------------- +float2 Scene(in float3 rO, in float3 rD, in float2 fragCoord) + { + float t=.05+0.05*Texture(fragCoord.xy/256).y;//texture(iChannel0, fragCoord.xy / iChannelResolution[0].xy).y; + float3 p=float3(0.0,0.0,0.0); + float oldT=0.0; + bool hit=false; + float glow=0.0; + float2 dist; + for(int j=0; j < 100; j++) + { + if(t > 12.0) + break; + p=rO+t*rD; + + float h=Map(p); + + if(h<0.0005) + { + dist=float2(oldT,t); + hit=true; + break; + } + glow+=clamp(.05-h,0.0,.4); + oldT=t; + t+=h+t*0.001; + } + if(!hit) + t=1000.0; + else + t=BinarySubdivision(rO, rD, dist); + return float2(t,clamp(glow*.25, 0.0, 1.0)); + + } + +//---------------------------------------------------------------------------------------- +float Hash(float2 p) + { + return frac(sin(dot(p,float2(12.9898,78.233)))*33758.5453)-.5; + } + +//---------------------------------------------------------------------------------------- +float3 PostEffects(float3 rgb, float2 xy) + { +// Gamma first... + + +// Then... +#define CONTRAST 1.08 +#define SATURATION 1.5 +#define BRIGHTNESS 1.5 + float tmp=dot(float3(.2125, .7154, .0721),rgb*BRIGHTNESS); + rgb=lerp(float3(0.5,0.5,0.5),lerp(float3(tmp,tmp,tmp),rgb*BRIGHTNESS,SATURATION),CONTRAST); +// Noise... +//rgb = clamp(rgb+Hash(xy*iTime)*.1, 0.0, 1.0); +// Vignette... + rgb*=.5+0.5*pow(20.0*xy.x*xy.y*(1.0-xy.x)*(1.0-xy.y), 0.2); + + rgb=pow(rgb,float3(0.47,0.47,0.47)); + return rgb; + } + +//---------------------------------------------------------------------------------------- +float Shadow(in float3 ro, in float3 rd) + { + float res=1.0; + float t=0.05; + float h; + + for(int i = 0; i < 8; i++) + { + h=Map(ro+rd*t); + res=min(6.0*h/t,res); + t+=h; + } + return max(res, 0.0); + } + +//---------------------------------------------------------------------------------------- +float3x3 RotationMatrix(float3 axis, float angle) + { + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return float3x3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); + } + +//---------------------------------------------------------------------------------------- +float3 LightSource(float3 spotLight, float3 dir, float dis) + { + float g=0.0; + if(length(spotLight) < dis) + { + g=pow(max(dot(normalize(spotLight),dir),0.0),200.0); + } + + return(g*sunColour.rgb*sunColour.a); + } + +//---------------------------------------------------------------------------------------- +float3 CameraPath(float t) + { + float3 p=float3(-0.78+3.0*sin(2.14*t),0.05+2.5*sin(0.942*t+1.3),.05+3.5*cos(3.594*t)); + return p; + } + +//---------------------------------------------------------------------------------------- +float4 mainImage(float2 fragCoord) + { + //float m=(iMouse.x/iResolution.x)*300.0; + //gTime = iTime+m*.01 + 15.00; + float gTime=iTime*0.01; + float2 xy =fragCoord/iResolution; + float2 uv =(-1.0+2.0*xy)*float2(iResolution.x/iResolution.y,1.0); + + //return(float4(uv,0.0,1.0)); + + float3 cameraPos=CameraPath(gTime); + float3 camTar =CameraPath(gTime+.01); + + float roll=13.0*sin(gTime*.5+.4); + float3 cw=normalize(camTar-cameraPos); + + float3 cp=float3(sin(roll),cos(roll),0.0); + float3 cu=normalize(cross(cw,cp)); + + float3 cv=normalize(cross(cu,cw)); + cw=mul(cw,RotationMatrix(cv,sin(-gTime*20.0)*.7)); + float3 dir=normalize(uv.x*cu+uv.y*cv+1.3*cw); + + float3 spotLight=CameraPath(gTime+.03)+float3(sin(gTime*18.4),cos(gTime*17.98),sin(gTime*22.53))*.2; + float3 col=float3(0.0,0.0,0.0); + float3 sky=float3(0.03,.04,.05)*GetSky(dir); + float2 ret=Scene(cameraPos,dir,fragCoord); + + if(ret.x<900.0) + { + float3 p=cameraPos+ret.x*dir; + float3 nor=GetNormal(p,ret.x); + + float3 spot=spotLight-p; + float atten=length(spot); + + spot/=atten; + + float shaSpot=Shadow(p,spot); + float shaSun=Shadow(p,sunDir); + + float bri=max(dot(spot,nor),0.0)/pow(atten,1.5)*.15; + float briSun=max(dot(sunDir,nor),0.0)*.3; + + col=Colour(p,ret.x); + col=(col*bri*shaSpot)+(col*briSun*shaSun); + + float3 ref=reflect(dir,nor); + col+=pow(max(dot(spot,ref),0.0), 10.0)*2.0*shaSpot*bri; + col+=pow(max(dot(sunDir,ref),0.0),10.0)*2.0*shaSun *bri; + } + + col=lerp(sky,col,min(exp(-ret.x+1.5),1.0)); + col+=(float3)pow(abs(ret.y),2.) * float3(.02, .04, .1); + + col+=LightSource(spotLight-cameraPos,dir,ret.x); + col=PostEffects(col, xy); + + return(float4(col,1.0)); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +float4 main(PSInput input) : SV_TARGET + { + return(mainImage(input.position.xy)); + } +//+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl new file mode 100644 index 000000000..f33905108 --- /dev/null +++ b/tests/3D/Shaders/vertex.hlsl @@ -0,0 +1,18 @@ +struct VSInput + { + float4 position : POSITION; + }; + +struct PSInput + { + float4 position : SV_POSITION; + }; + +PSInput main(VSInput input) + { + PSInput output; + + output.position=(input.position); + + return(output); + } \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 new file mode 100644 index 000000000..a45a946fa --- /dev/null +++ b/tests/3DTest.mq5 @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of 3D visualization classes. + */ + +// Resources. +#resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; +#resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; + +// Includes. +#include "../3D/Frontends/MT5Frontend.h" +#include "../3D/Devices/MTDX/MTDXDevice.h" +#include "../3D/Devices/MTDX/MTDXIndexBuffer.h" +#include "../3D/Devices/MTDX/MTDXShader.h" +#include "../3D/Devices/MTDX/MTDXVertexBuffer.h" +#include "../Test.mqh" + +struct Vertex { + float position[4]; +}; + +const ShaderVertexLayout VertexLayout[1] = { + { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 } +}; + +/** + * Implements OnStart(). + */ +int OnStart() { + Ref gfx_ptr = new MTDXDevice(); + Device* gfx = gfx_ptr.Ptr(); + + gfx.Start(new MT5Frontend()); + + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); + Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + + Vertex vertices[]= {{{-1,-1,0.5,1.0}},{{-1,1,0.5,1.0}},{{1,1,0.5,1.0}},{{1,-1,0.5,1.0}}}; + + while (!IsStopped()) + { + gfx.Begin().Clear(); + + gfx.End(); + } + + + gfx.Stop(); + + return (INIT_SUCCEEDED); +} From 6fcc775d78b63d7248033cfe720afb88d820d553 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 20 Apr 2021 19:26:21 +0200 Subject: [PATCH 13/97] WIP. Closer to 3d objects rendering. --- 3D/Device.h | 43 ++++++++++++++++-- 3D/Devices/MTDX/MTDXDevice.h | 52 +++++++++++++++++----- 3D/Devices/MTDX/MTDXIndexBuffer.h | 12 ++++- 3D/Devices/MTDX/MTDXShader.h | 36 ++++++++++++++- 3D/Devices/MTDX/MTDXVertexBuffer.h | 25 ++++++++++- 3D/Frontend.h | 12 +++++ 3D/Frontends/MT5Frontend.h | 70 +++++++++++++++++++++++++++++- 3D/Shader.h | 2 + 3D/VertexBuffer.h | 7 +-- tests/3DTest.mq5 | 59 +++++++++++++++++++++---- 10 files changed, 283 insertions(+), 35 deletions(-) diff --git a/3D/Device.h b/3D/Device.h index 7c3925829..192222206 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -10,17 +10,29 @@ enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH } * Graphics device. */ class Device : public Dynamic { +protected: + + int context; + Ref frontend; + public: - bool Start(Frontend* _frontend) { return Init(_frontend); } + + bool Start(Frontend* _frontend) { + frontend = _frontend; + return Init(_frontend); + } - Device* Begin() { - Clear(0x000000); + Device* Begin(unsigned int clear_color = 0xFF000000) { + frontend.Ptr().RenderBegin(context); + ClearDepth(); + Clear(clear_color); RenderBegin(); return &this; } Device* End() { RenderEnd(); + frontend.Ptr().RenderEnd(context); return &this; } @@ -38,6 +50,11 @@ class Device : public Dynamic { ClearBuffer(CLEAR_BUFFER_TYPE_DEPTH, 0); return &this; } + + /** + * Returns graphics device context as integer. + */ + int Context() { return context; } /** * Creates index buffer to be used by current graphics device. @@ -55,10 +72,30 @@ class Device : public Dynamic { */ virtual Shader* PixelShader(string _source_code, string _entry_point = "main") = NULL; + /** + * Creates vertex buffer to be used by current graphics device. + */ + template + VertexBuffer* VertexBuffer(T& data[]) { + VertexBuffer* _buff = VertexBuffer(); + // Unfortunately we can't make this method virtual. + if (dynamic_cast(_buff) != NULL) { + // MT5's DirectX. + Print("Filling vertex buffer via MTDXVertexBuffer"); + ((MTDXVertexBuffer*)_buff).Fill(data); + } + else { + Alert("Unsupported vertex buffer device target"); + } + return _buff; + } + /** * Creates vertex buffer to be used by current graphics device. */ virtual VertexBuffer* VertexBuffer() = NULL; + + virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; protected: /** diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 6094184f1..560c977ff 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -1,34 +1,41 @@ #include "../../Device.h" class MTDXDevice : public Device { - protected: - int context; - public: /** * Initializes graphics device. */ bool Init(Frontend* _frontend) { + Print("MTDXDevice: DXContextCreate: width = ", _frontend.Width(), ", height = ", _frontend.Height()); context = DXContextCreate(_frontend.Width(), _frontend.Height()); - + Print("LastError: ", GetLastError()); + Print("MTDXDevice: context = ", context); + _frontend.Init(); return true; } /** * Deinitializes graphics device. */ - bool Deinit() { return true; } + bool Deinit() { + DXRelease(context); + return true; + } /** * Starts rendering loop. */ - virtual bool RenderBegin() { return true; } + virtual bool RenderBegin() { + return true; + } /** * Ends rendering loop. */ - virtual bool RenderEnd() { return true; } - + virtual bool RenderEnd() { + return true; + } + /** * Returns DX context's id. */ @@ -42,11 +49,16 @@ class MTDXDevice : public Device { */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color = 0x000000) { if (_type == CLEAR_BUFFER_TYPE_COLOR) { - DXVector _dx_color; - _dx_color.x = 1; + DXVector _dx_color; + _dx_color.x = 1.0f / 255.0f * ((_color & 0x00FF0000) >> 16); + _dx_color.y = 1.0f / 255.0f * ((_color & 0x0000FF00) >> 8); + _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); + _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); + Print("LastError: ", GetLastError()); } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); + Print("LastError: ", GetLastError()); } } @@ -77,5 +89,23 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { return NULL; } + VertexBuffer* VertexBuffer() { + return new MTDXVertexBuffer(&this); + } + + virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { + _vertices.Select(); + DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + if (_indices == NULL) { + if (!DXDraw(context)) { + Print("Can't draw!"); + } + Print("DXDraw: LastError: ", GetLastError()); + } + else { + //_indices.Select(); + DXDrawIndexed(context); + } + + } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 53109e770..54cbc862e 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -2,12 +2,20 @@ class MTDXIndexBuffer : public IndexBuffer { MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} + +protected: + + int handle; /** * Creates index buffer. */ virtual bool Create(void*& _data[]) { - // DXBufferCreate(((MTDXDevice*)Device()).Context(), DX_BUFFER_INDEX, &_data); - return true; + //handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); + return handle != INVALID_HANDLE; + } + + ~MTDXIndexBuffer() { + //DXRelease() } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index ccab5aae3..fe73257f1 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -9,7 +9,7 @@ class MTDXShader : public Shader { bool Create(ENUM_SHADER_TYPE _type, string _source_code, string _entry_point = "main") { string error_text; - handle = DXShaderCreate(((MTDXDevice *)GetDevice()).Context(), + handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, error_text); @@ -20,6 +20,38 @@ class MTDXShader : public Shader { * Sets vertex/pixel data layout to be used by shader. */ virtual void SetDataLayout(const ShaderVertexLayout &_layout[]) { - // DXShaderSetLayout(handle, _layout); + // Converting generic layout into MT5 DX's one. + + DXVertexLayout _target_layout[]; + ArrayResize(_target_layout, ArraySize(_layout)); + + for (int i = 0; i < ArraySize(_layout); ++i) { + _target_layout[i].semantic_name = _layout[i].name; + _target_layout[i].semantic_index = _layout[i].index; + _target_layout[i].format = ParseFormat(_layout[i]); + } + + DXShaderSetLayout(handle, _target_layout); + Print("DXShaderSetLayout: LastError: ", GetLastError()); + } + + ENUM_DX_FORMAT ParseFormat(const ShaderVertexLayout& _layout) { + if (_layout.type == GFX_VAR_TYPE_FLOAT) { + switch (_layout.num_components) { + case 1: return DX_FORMAT_R32_FLOAT; + case 2: return DX_FORMAT_R32G32_FLOAT; + case 3: return DX_FORMAT_R32G32B32_FLOAT; + case 4: return DX_FORMAT_R32G32B32A32_FLOAT; + default: + Alert("Too many components in vertex layout!"); + } + } + + Alert("Wrong vertex layout!"); + return (ENUM_DX_FORMAT)0; + } + + virtual void Select() { + DXShaderSet(GetDevice().Context(), handle); } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index d6fe42414..afb844e15 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -1,12 +1,33 @@ #include "../../VertexBuffer.h" class MTDXVertexBuffer : public VertexBuffer { + + int handle; + public: + + MTDXVertexBuffer(Device *_device) : VertexBuffer(_device) {} + + ~MTDXVertexBuffer() { + DXRelease(handle); + } + +public: + /** * Creates vertex buffer. */ - virtual bool Create(void*& _data[]) { - DXBufferCreate(((MTDXDevice*)GetDevice()).Context(), DX_BUFFER_VERTEX, _data); + template + bool Fill(X& _data[]) { + handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_VERTEX, _data); + Print("Created vb ", handle); + Print("Fill: LastError: ", GetLastError()); return true; } + + virtual void Select() { + Print("Selecting vb ", handle); + DXBufferSet(GetDevice().Context(), handle); + Print("Select: LastError: ", GetLastError()); + } }; \ No newline at end of file diff --git a/3D/Frontend.h b/3D/Frontend.h index 6415d7c00..e0696eaa9 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -25,6 +25,18 @@ class Frontend : public Dynamic { */ virtual bool Deinit() = NULL; + /** + * Executed before render starts. + */ + virtual void RenderBegin(int context) = NULL; + + /** + * Executed after render ends. + */ + virtual void RenderEnd(int context) = NULL; + + virtual void Refresh(int context) {}; + /** * Returns canvas' width. */ diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 5ff154f38..a2c9e51a8 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -4,14 +4,82 @@ * MetaTrader 5 chart target. */ class MT5Frontend : public Frontend { + unsigned int image[]; + int last_width, last_height; + string resname; + string objname; + +public: + virtual bool Init() { // Hiding 2D chart. ChartSetInteger(0, CHART_SHOW, false); ChartRedraw(); + + Print("LastError: ", GetLastError()); + + objname = "MT5_Frontend_" + IntegerToString(ChartID()); + resname = "::MT5_Frontend" + IntegerToString(ChartID()); + ObjectCreate(0, objname, OBJ_BITMAP_LABEL, 0, 0, 0); + ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 0); + ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 0); + Print("LastError: ", GetLastError()); + + Print("LastError: ", GetLastError()); + Print("ResourceCreate: width = ", Width(), ", height = ", Height()); + ObjectSetString(ChartID(), objname, OBJPROP_BMPFILE, resname); + Print("LastError: ", GetLastError()); return true; } - virtual bool Deinit() { return true; } + virtual bool Deinit() { + ResourceFree(resname); + ObjectDelete(0, objname); + ChartSetInteger(0, CHART_SHOW, true); + return true; + } + + bool Resize() { + if (Width() == last_width && Height() == last_height) { + return false; + } + + ArrayResize(image, Width() * Height()); + Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + Print("ResourceCreate: LastError: ", GetLastError()); + + last_width = Width(); + last_height = Height(); + + return true; + } + + virtual void RenderBegin(int context) { + Print("MT5Frontend: RenderBegin()"); + Print("Image resize: width = ", Width(), ", height = ", Height()); + + if (Resize()) { + DXContextSetSize(context, Width(), Height()); + } + + Print("DXContextSetSize: LastError: ", GetLastError()); + } + + virtual void RenderEnd(int context) { + Print("MT5Frontend: RenderEnd()"); + Print("ResourceCreate: width = ", Width(), ", height = ", Height()); + Print("MT5Frontend: DXContextGetColors()"); + DXContextGetColors(context, image); + Print("DXContextGetColors: LastError: ", GetLastError()); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + Print("ResourceCreate: LastError: ", GetLastError()); + ChartRedraw(); + Sleep(1); + } + + virtual void Refresh(int context) { + } virtual int Width() { return (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); } diff --git a/3D/Shader.h b/3D/Shader.h index e013d54c0..258743293 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -35,4 +35,6 @@ class Shader : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } + + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h index 36ad0b53f..cf3f600f4 100644 --- a/3D/VertexBuffer.h +++ b/3D/VertexBuffer.h @@ -13,9 +13,6 @@ class VertexBuffer : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } - - /** - * Creates index buffer. - */ - virtual bool Create(void*& _data[]) = NULL; + + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index a45a946fa..c39d61b8f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -37,34 +37,75 @@ #include "../Test.mqh" struct Vertex { - float position[4]; + float Position[4]; + float Color[4]; }; -const ShaderVertexLayout VertexLayout[1] = { - { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 } +const ShaderVertexLayout VertexLayout[2] = { + { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 }, + { "COLOR", 1, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*4 }, }; +#define GFX_DEVICE MTDXDevice + +#ifdef __MQL__ + #define FILL_VERTEX_BUFFER(BUFFER, T, VERTICES) ((MTDXVertexBuffer*)BUFFER).Fill(VERTICES) +#endif + +int OnStart() { + return OnInit(); +} + /** * Implements OnStart(). */ -int OnStart() { - Ref gfx_ptr = new MTDXDevice(); +int OnInit() { + Ref gfx_ptr = new GFX_DEVICE(); + Print("Device initialized"); Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); + Print("Front-end initialized"); + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + //Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + + Vertex vertices[]= { + { + {-1,-1,0.5,1.0}, + {1, 0, 0, 1}, + }, + { + {-1,1,0.5,1.0}, + {0, 1, 0, 1}, + }, + { + {1,1,0.5,1.0}, + {0, 0, 1, 1}, + }, + { + {1,-1,0.5,1.0}, + {1, 0, 1, 1}, + } + }; - Vertex vertices[]= {{{-1,-1,0.5,1.0}},{{-1,1,0.5,1.0}},{{1,1,0.5,1.0}},{{1,-1,0.5,1.0}}}; + Ref _vbuff = gfx.VertexBuffer(vertices); while (!IsStopped()) { - gfx.Begin().Clear(); + if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { + break; + } + + gfx.Begin(0xFF00FF00); + + _shader_v.Ptr().Select(); + + gfx.Render(_vbuff.Ptr()); gfx.End(); } - gfx.Stop(); From 3fadca7fe0b4372b6c50ae8ba22d30b9a7f8c022 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 21 Apr 2021 18:06:45 +0200 Subject: [PATCH 14/97] WIP. Can't force MT5 to render any triangles :( --- 3D/Device.h | 33 ++- 3D/Devices/MTDX/MTDXDevice.h | 19 +- 3D/Devices/MTDX/MTDXIndexBuffer.h | 25 ++- 3D/Devices/MTDX/MTDXShader.h | 10 + 3D/Frontends/MT5Frontend.h | 2 +- 3D/IndexBuffer.h | 10 + tests/3D/Shaders/pixel.hlsl | 330 +----------------------------- tests/3D/Shaders/vertex.hlsl | 23 ++- tests/3DTest.mq5 | 57 +++--- 9 files changed, 130 insertions(+), 379 deletions(-) diff --git a/3D/Device.h b/3D/Device.h index 192222206..e1c57b052 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -22,7 +22,7 @@ class Device : public Dynamic { return Init(_frontend); } - Device* Begin(unsigned int clear_color = 0xFF000000) { + Device* Begin(unsigned int clear_color = 0) { frontend.Ptr().RenderBegin(context); ClearDepth(); Clear(clear_color); @@ -56,11 +56,6 @@ class Device : public Dynamic { */ int Context() { return context; } - /** - * Creates index buffer to be used by current graphics device. - */ - virtual IndexBuffer* IndexBuffer() = NULL; - /** * Creates vertex shader to be used by current graphics device. */ @@ -94,10 +89,34 @@ class Device : public Dynamic { * Creates vertex buffer to be used by current graphics device. */ virtual VertexBuffer* VertexBuffer() = NULL; - + + /** + * Creates index buffer to be used by current graphics device. + */ + virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; + + /** + * Renders vertex buffer with optional point indices. + */ virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + + /** + * Activates shader for rendering. + */ + void SetShader(Shader *_shader) { + _shader.Select(); + } + + /** + * Activates shaders for rendering. + */ + void SetShader(Shader *_shader1, Shader *_shader2) { + _shader1.Select(); + _shader2.Select(); + } protected: + /** * Initializes graphics device. */ diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 560c977ff..1777b485c 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -55,10 +55,10 @@ class MTDXDevice : public Device { _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); - Print("LastError: ", GetLastError()); + Print("DXContextClearColors: LastError: ", GetLastError()); } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); - Print("LastError: ", GetLastError()); + Print("DXContextClearDepth: LastError: ", GetLastError()); } } @@ -93,9 +93,18 @@ class MTDXDevice : public Device { return new MTDXVertexBuffer(&this); } + /** + * Creates index buffer to be used by current graphics device. + */ + virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) { + IndexBuffer* _buffer = new MTDXIndexBuffer(&this); + _buffer.Fill(_indices); + return _buffer; + } + virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { - _vertices.Select(); DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + _vertices.Select(); if (_indices == NULL) { if (!DXDraw(context)) { Print("Can't draw!"); @@ -103,9 +112,9 @@ class MTDXDevice : public Device { Print("DXDraw: LastError: ", GetLastError()); } else { - //_indices.Select(); + _indices.Select(); DXDrawIndexed(context); + Print("DXDrawIndexed: LastError: ", GetLastError()); } - } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 54cbc862e..6b305c832 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -1,6 +1,8 @@ #include "../../IndexBuffer.h" class MTDXIndexBuffer : public IndexBuffer { +public: + MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} protected: @@ -14,8 +16,27 @@ class MTDXIndexBuffer : public IndexBuffer { //handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); return handle != INVALID_HANDLE; } - + + /** + * Destructor; + */ ~MTDXIndexBuffer() { - //DXRelease() + DXRelease(handle); + } + + /** + * Fills index buffer with indices. + */ + virtual void Fill(unsigned int& _indices[]) { + handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_INDEX, _indices); + } + + /** + * Activates index buffer for rendering. + */ + virtual void Select() { + Print("Selecting indices ", handle); + DXBufferSet(GetDevice().Context(), handle); + Print("Select: LastError: ", GetLastError()); } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index fe73257f1..ebd53a41c 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -12,6 +12,8 @@ class MTDXShader : public Shader { handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, error_text); + + Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); return true; } @@ -25,14 +27,22 @@ class MTDXShader : public Shader { DXVertexLayout _target_layout[]; ArrayResize(_target_layout, ArraySize(_layout)); + Print("ArrayResize: LastError: ", GetLastError()); + for (int i = 0; i < ArraySize(_layout); ++i) { _target_layout[i].semantic_name = _layout[i].name; _target_layout[i].semantic_index = _layout[i].index; _target_layout[i].format = ParseFormat(_layout[i]); + + Print(_target_layout[i].semantic_name, "@", i, ": ", EnumToString(_target_layout[i].format)); } + + Print("before DXShaderSetLayout: LastError: ", GetLastError()); DXShaderSetLayout(handle, _target_layout); Print("DXShaderSetLayout: LastError: ", GetLastError()); + + ResetLastError(); } ENUM_DX_FORMAT ParseFormat(const ShaderVertexLayout& _layout) { diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index a2c9e51a8..5a9ea8713 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -75,7 +75,7 @@ class MT5Frontend : public Frontend { ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); Print("ResourceCreate: LastError: ", GetLastError()); ChartRedraw(); - Sleep(1); + Sleep(50); } virtual void Refresh(int context) { diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h index 4279991f8..230532002 100644 --- a/3D/IndexBuffer.h +++ b/3D/IndexBuffer.h @@ -23,4 +23,14 @@ class IndexBuffer : public Dynamic { * Creates index buffer. */ virtual bool Create(void*& _data[]) = NULL; + + /** + * Fills index buffer with indices. + */ + virtual void Fill(unsigned int& _indices[]) = NULL; + + /** + * Activates index buffer for rendering. + */ + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index 9445e5732..f985e1f0a 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,328 +1,10 @@ -// Remnant X -// by David Hoskins. -// Thanks to boxplorer and the folks at 'Fractalforums.com' -// HD Video:- https://www.youtube.com/watch?v=BjkK9fLXXo0 -// https://www.shadertoy.com/view/4sjSW1 - struct PSInput - { - float4 position : SV_POSITION; - }; - -cbuffer Input - { - float2 iResolution; - float iTime; - float iDummy; - }; - -#define PI 3.14159265f -#define SCALE 2.8 -#define MINRAD2 .25 -#define scale (float4(SCALE, SCALE, SCALE, abs(SCALE)) / minRad2) - -static const float minRad2 = clamp(MINRAD2, 1.0e-9, 1.0); -static const float absScalem1 = abs(SCALE - 1.0); -static const float AbsScaleRaisedTo1mIters = pow(abs(SCALE), float(1-10)); -static const float3 surfaceColour1 = float3(.8, .0, 0.); -static const float3 surfaceColour2 = float3(.4, .4, 0.5); -static const float3 surfaceColour3 = float3(.5, 0.3, 0.00); -static const float3 fogCol = float3(0.4, 0.4, 0.4); - -static const float3 sunDir=normalize(float3(0.35,0.1,0.3)); -static const float4 sunColour=float4(1.0,0.95,0.8,0.2); - - -float2 Rand(float2 p) - { - return(float2(frac(sin(dot(p,float2(12.9898,78.233)))*6.7416516),frac(sin(dot(p,float2(58.6542,22.6546)))*6.5465145))); - } - -float2 Texture(float2 p) - { - float2 p1=Rand(floor(p*256+float2(0,0))); - float2 p2=Rand(floor(p*256+float2(0,1))); - float2 p3=Rand(floor(p*256+float2(1,0))); - float2 p4=Rand(floor(p*256+float2(1,1))); - float2 f =frac(p*256); - - return lerp(lerp(p1,p2,f.y),lerp(p3,p4,f.y),f.x); - } - -//---------------------------------------------------------------------------------------- -float Noise(in float3 x) - { - float3 p=floor(x); - float3 f=frac(x); - f=f*f*(3.0-2.0*f); - - float2 uv=(p.xy+float2(37.0,17.0)*p.z)+f.xy; - float2 rg=Rand((uv+0.5)/256.0).yx;//texture(iChannel0,(uv+0.5)/256.0,-99.0).yx; - return lerp(rg.x,rg.y,f.z); - } - -//---------------------------------------------------------------------------------------- -float Map(float3 pos) - { - - float4 p=float4(pos,1); - float4 p0=p; // p.w is the distance estimate - - for(int i = 0; i < 9; i++) - { - p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; - - float r2=dot(p.xyz,p.xyz); - p*=clamp(max(minRad2/r2,minRad2),0.0,1.0); - - // scale, translate - p=p*scale+p0; - } - return ((length(p.xyz)-absScalem1)/p.w-AbsScaleRaisedTo1mIters); - } - -//---------------------------------------------------------------------------------------- -float3 Colour(float3 pos, float sphereR) - { - float3 p=pos; - float3 p0=p; - float trap=1.0; - - for(int i = 0; i < 6; i++) - { - p.xyz=clamp(p.xyz,-1.0,1.0)*2.0-p.xyz; - float r2 = dot(p.xyz,p.xyz); - p*=clamp(max(minRad2/r2,minRad2), 0.0, 1.0); - - p=p*scale.xyz+p0.xyz; - trap=min(trap,r2); - } -// |c.x|: log final distance (fractional iteration count) -// |c.y|: spherical orbit trap at (0,0,0) - float2 c=clamp(float2(0.3333*log(dot(p,p))-1.0,sqrt(trap)),0.0, 1.0); - - float t=fmod(length(pos)-iTime*1.5,16.0); - float3 surfaceColour=lerp(surfaceColour1,float3(0.4,3.0,5.0),pow(smoothstep(0.0,0.3,t)*smoothstep(0.6,.3,t),10.0)); - return lerp(lerp(surfaceColour,surfaceColour2,c.y),surfaceColour3,c.x); - } - - -//---------------------------------------------------------------------------------------- -float3 GetNormal(float3 pos, float distance) - { - distance*=0.001+.0001; - float2 eps=float2(distance,0.0); - float3 nor=float3(Map(pos+eps.xyy) - Map(pos-eps.xyy), - Map(pos+eps.yxy) - Map(pos-eps.yxy), - Map(pos+eps.yyx) - Map(pos-eps.yyx)); - return normalize(nor); - } - -//---------------------------------------------------------------------------------------- -float GetSky(float3 pos) - { - pos*=0.02; - float2 t=0.5 *Texture(pos.xy*2.1) +0.5*Texture(pos.yz*2.3-(float2)0.53) +0.5*Texture(pos.zx*1.9+(float2)0.47)+ - 0.25 *Texture(pos.xy*4.7) +0.25*Texture(pos.yz*4.1+(float2)0.71) +0.25*Texture(pos.zx*4.3+(float2)0.59)+ - 0.125*Texture(pos.xy*8.7)+0.125*Texture(pos.yz*8.6-(float2)0.69)+0.125*Texture(pos.zx*8.3+(float2)0.95); - - return(pow(t.x*t.y,0.5)); - } - -//---------------------------------------------------------------------------------------- -float BinarySubdivision(in float3 rO, in float3 rD, float2 t) - { - float halfwayT; - - for(int i = 0; i < 6; i++) - { - - halfwayT=dot(t,float2(0.5,0.5)); - float d = Map(rO + halfwayT*rD); - //if (abs(d) < 0.001) break; - t=lerp(float2(t.x,halfwayT),float2(halfwayT,t.y),step(0.0005, d)); - } - - return halfwayT; - } - -//---------------------------------------------------------------------------------------- -float2 Scene(in float3 rO, in float3 rD, in float2 fragCoord) - { - float t=.05+0.05*Texture(fragCoord.xy/256).y;//texture(iChannel0, fragCoord.xy / iChannelResolution[0].xy).y; - float3 p=float3(0.0,0.0,0.0); - float oldT=0.0; - bool hit=false; - float glow=0.0; - float2 dist; - for(int j=0; j < 100; j++) - { - if(t > 12.0) - break; - p=rO+t*rD; - - float h=Map(p); - - if(h<0.0005) - { - dist=float2(oldT,t); - hit=true; - break; - } - glow+=clamp(.05-h,0.0,.4); - oldT=t; - t+=h+t*0.001; - } - if(!hit) - t=1000.0; - else - t=BinarySubdivision(rO, rD, dist); - return float2(t,clamp(glow*.25, 0.0, 1.0)); +{ + float4 color : COLOR0; +}; - } - -//---------------------------------------------------------------------------------------- -float Hash(float2 p) - { - return frac(sin(dot(p,float2(12.9898,78.233)))*33758.5453)-.5; - } - -//---------------------------------------------------------------------------------------- -float3 PostEffects(float3 rgb, float2 xy) - { -// Gamma first... - - -// Then... -#define CONTRAST 1.08 -#define SATURATION 1.5 -#define BRIGHTNESS 1.5 - float tmp=dot(float3(.2125, .7154, .0721),rgb*BRIGHTNESS); - rgb=lerp(float3(0.5,0.5,0.5),lerp(float3(tmp,tmp,tmp),rgb*BRIGHTNESS,SATURATION),CONTRAST); -// Noise... -//rgb = clamp(rgb+Hash(xy*iTime)*.1, 0.0, 1.0); -// Vignette... - rgb*=.5+0.5*pow(20.0*xy.x*xy.y*(1.0-xy.x)*(1.0-xy.y), 0.2); - - rgb=pow(rgb,float3(0.47,0.47,0.47)); - return rgb; - } - -//---------------------------------------------------------------------------------------- -float Shadow(in float3 ro, in float3 rd) - { - float res=1.0; - float t=0.05; - float h; - - for(int i = 0; i < 8; i++) - { - h=Map(ro+rd*t); - res=min(6.0*h/t,res); - t+=h; - } - return max(res, 0.0); - } - -//---------------------------------------------------------------------------------------- -float3x3 RotationMatrix(float3 axis, float angle) - { - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return float3x3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); - } - -//---------------------------------------------------------------------------------------- -float3 LightSource(float3 spotLight, float3 dir, float dis) - { - float g=0.0; - if(length(spotLight) < dis) - { - g=pow(max(dot(normalize(spotLight),dir),0.0),200.0); - } - - return(g*sunColour.rgb*sunColour.a); - } - -//---------------------------------------------------------------------------------------- -float3 CameraPath(float t) - { - float3 p=float3(-0.78+3.0*sin(2.14*t),0.05+2.5*sin(0.942*t+1.3),.05+3.5*cos(3.594*t)); - return p; - } - -//---------------------------------------------------------------------------------------- -float4 mainImage(float2 fragCoord) - { - //float m=(iMouse.x/iResolution.x)*300.0; - //gTime = iTime+m*.01 + 15.00; - float gTime=iTime*0.01; - float2 xy =fragCoord/iResolution; - float2 uv =(-1.0+2.0*xy)*float2(iResolution.x/iResolution.y,1.0); - - //return(float4(uv,0.0,1.0)); - - float3 cameraPos=CameraPath(gTime); - float3 camTar =CameraPath(gTime+.01); - - float roll=13.0*sin(gTime*.5+.4); - float3 cw=normalize(camTar-cameraPos); - - float3 cp=float3(sin(roll),cos(roll),0.0); - float3 cu=normalize(cross(cw,cp)); - - float3 cv=normalize(cross(cu,cw)); - cw=mul(cw,RotationMatrix(cv,sin(-gTime*20.0)*.7)); - float3 dir=normalize(uv.x*cu+uv.y*cv+1.3*cw); - - float3 spotLight=CameraPath(gTime+.03)+float3(sin(gTime*18.4),cos(gTime*17.98),sin(gTime*22.53))*.2; - float3 col=float3(0.0,0.0,0.0); - float3 sky=float3(0.03,.04,.05)*GetSky(dir); - float2 ret=Scene(cameraPos,dir,fragCoord); - - if(ret.x<900.0) - { - float3 p=cameraPos+ret.x*dir; - float3 nor=GetNormal(p,ret.x); - - float3 spot=spotLight-p; - float atten=length(spot); - - spot/=atten; - - float shaSpot=Shadow(p,spot); - float shaSun=Shadow(p,sunDir); - - float bri=max(dot(spot,nor),0.0)/pow(atten,1.5)*.15; - float briSun=max(dot(sunDir,nor),0.0)*.3; - - col=Colour(p,ret.x); - col=(col*bri*shaSpot)+(col*briSun*shaSun); - - float3 ref=reflect(dir,nor); - col+=pow(max(dot(spot,ref),0.0), 10.0)*2.0*shaSpot*bri; - col+=pow(max(dot(sunDir,ref),0.0),10.0)*2.0*shaSun *bri; - } - - col=lerp(sky,col,min(exp(-ret.x+1.5),1.0)); - col+=(float3)pow(abs(ret.y),2.) * float3(.02, .04, .1); - - col+=LightSource(spotLight-cameraPos,dir,ret.x); - col=PostEffects(col, xy); - - return(float4(col,1.0)); - } - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ float4 main(PSInput input) : SV_TARGET - { - return(mainImage(input.position.xy)); - } +{ + return float4(1.0f, 0.0f, 1.0f, 1.0f); +} //+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index f33905108..5d31ddf5f 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -1,18 +1,19 @@ struct VSInput - { - float4 position : POSITION; - }; - +{ + float3 position : POSITION; + float4 color : COLOR0; +}; + struct PSInput - { - float4 position : SV_POSITION; - }; +{ + float4 color : COLOR0; +}; PSInput main(VSInput input) - { +{ PSInput output; - output.position=(input.position); + output.color = float4(1, 1, 1, 1); - return(output); - } \ No newline at end of file + return output; +} \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index c39d61b8f..f66e9571b 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -36,61 +36,60 @@ #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../Test.mqh" +int OnStart() { + return OnInit(); +} + struct Vertex { - float Position[4]; + float Position[3]; float Color[4]; }; -const ShaderVertexLayout VertexLayout[2] = { - { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), 0 }, - { "COLOR", 1, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*4 }, +const ShaderVertexLayout VertexLayout[] = { + { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0 }, + { "COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*3 }, }; -#define GFX_DEVICE MTDXDevice - -#ifdef __MQL__ - #define FILL_VERTEX_BUFFER(BUFFER, T, VERTICES) ((MTDXVertexBuffer*)BUFFER).Fill(VERTICES) -#endif - -int OnStart() { - return OnInit(); -} - /** * Implements OnStart(). */ int OnInit() { - Ref gfx_ptr = new GFX_DEVICE(); - Print("Device initialized"); - Device* gfx = gfx_ptr.Ptr(); + Ref gfx_ptr = new MTDXDevice(); + Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); - Print("Front-end initialized"); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); - //Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref _shader_p = gfx.PixelShader(ShaderSourcePS); Vertex vertices[]= { { - {-1,-1,0.5,1.0}, - {1, 0, 0, 1}, + {-0.5, -0.5, 0.5}, + { 1, 0, 0, 1}, }, { - {-1,1,0.5,1.0}, + {-0.5, 0.5, 0.5}, {0, 1, 0, 1}, }, { - {1,1,0.5,1.0}, + {0.5, 0.5, 0.5}, {0, 0, 1, 1}, }, { - {1,-1,0.5,1.0}, - {1, 0, 1, 1}, + {0.5, -0.5, 0.5}, + {0, 0, 1, 1}, } }; + + unsigned int indices[] = { + 0, 1, 2, + 2, 3, 0 + }; Ref _vbuff = gfx.VertexBuffer(vertices); + Ref _ibuff = gfx.IndexBuffer(indices); + + unsigned int _rand_color = rand() * 1256; while (!IsStopped()) { @@ -98,11 +97,11 @@ int OnInit() { break; } - gfx.Begin(0xFF00FF00); + gfx.Begin(_rand_color); - _shader_v.Ptr().Select(); + gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); - gfx.Render(_vbuff.Ptr()); + gfx.Render(_vbuff.Ptr(), _ibuff.Ptr()); gfx.End(); } From d0be95bb3ded501ef56827f4b6c346f98166db58 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 22 Apr 2021 20:29:41 +0200 Subject: [PATCH 15/97] Finally made MT5 to render object and move camera in 3D --- 3D/Device.h | 1 + 3D/Devices/MTDX/MTDXShader.h | 31 +++++++++++++++++++++++--- 3D/Frontends/MT5Frontend.h | 2 +- 3D/Shader.h | 14 ++++++++++++ tests/3D/Shaders/pixel.hlsl | 5 +++-- tests/3D/Shaders/vertex.hlsl | 22 +++++++++++++++---- tests/3DTest.mq5 | 42 +++++++++++++++++++++++++++--------- 7 files changed, 97 insertions(+), 20 deletions(-) diff --git a/3D/Device.h b/3D/Device.h index e1c57b052..71a952b58 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -3,6 +3,7 @@ #include "IndexBuffer.h" #include "Shader.h" #include "VertexBuffer.h" +#include "Math.h" enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index ebd53a41c..957ec122a 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -2,6 +2,7 @@ class MTDXShader : public Shader { int handle; + int cbuffer_handle; public: MTDXShader(Device *_device) : Shader(_device) {} @@ -14,6 +15,8 @@ class MTDXShader : public Shader { error_text); Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); + + cbuffer_handle = 0; return true; } @@ -29,17 +32,22 @@ class MTDXShader : public Shader { Print("ArrayResize: LastError: ", GetLastError()); - for (int i = 0; i < ArraySize(_layout); ++i) { + int i; + + for (i = 0; i < ArraySize(_layout); ++i) { _target_layout[i].semantic_name = _layout[i].name; _target_layout[i].semantic_index = _layout[i].index; _target_layout[i].format = ParseFormat(_layout[i]); - - Print(_target_layout[i].semantic_name, "@", i, ": ", EnumToString(_target_layout[i].format)); } + for (i = 0; i < ArraySize(_target_layout); ++i) { + Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", EnumToString(_target_layout[i].format)); + } + Print("before DXShaderSetLayout: LastError: ", GetLastError()); DXShaderSetLayout(handle, _target_layout); + Print("DXShaderSetLayout: LastError: ", GetLastError()); ResetLastError(); @@ -61,6 +69,23 @@ class MTDXShader : public Shader { return (ENUM_DX_FORMAT)0; } + template + void SetCBuffer(const X& data) { + if (cbuffer_handle == 0) { + cbuffer_handle = DXInputCreate(GetDevice().Context(), sizeof(X)); + Print("DXInputCreate: LastError: ", GetLastError()); + + int _input_handles[1]; + _input_handles[0] = cbuffer_handle; + + DXShaderInputsSet(handle, _input_handles); + Print("DXShaderInputsSet: LastError: ", GetLastError()); + } + + DXInputSet(cbuffer_handle, data); + Print("DXInputSet: LastError: ", GetLastError()); + } + virtual void Select() { DXShaderSet(GetDevice().Context(), handle); } diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 5a9ea8713..ef0caa6d2 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -75,7 +75,7 @@ class MT5Frontend : public Frontend { ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); Print("ResourceCreate: LastError: ", GetLastError()); ChartRedraw(); - Sleep(50); + Sleep(5); } virtual void Refresh(int context) { diff --git a/3D/Shader.h b/3D/Shader.h index 258743293..1ef91bd65 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -6,6 +6,7 @@ enum ENUM_SHADER_TYPE { }; class Device; +class MTDXShader; enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; @@ -36,5 +37,18 @@ class Shader : public Dynamic { */ Device* GetDevice() { return device.Ptr(); } + template + void SetCBuffer(const X& data) { + // Unfortunately we can't make this method virtual. + if (dynamic_cast(&this) != NULL) { + // MT5's DirectX. + Print("Setting CBuffer data for MT5"); + ((MTDXShader*)&this).SetCBuffer(data); + } + else { + Alert("Unsupported cbuffer device target"); + } + } + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index f985e1f0a..e4ddb278c 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,10 +1,11 @@ struct PSInput { - float4 color : COLOR0; + float4 position : SV_POSITION; + float4 color : COLOR; }; float4 main(PSInput input) : SV_TARGET { - return float4(1.0f, 0.0f, 1.0f, 1.0f); + return input.color; } //+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index 5d31ddf5f..6a92c8b1b 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -1,19 +1,33 @@ +cbuffer CBuffer +{ + matrix world; + matrix view; + matrix proj; +}; + struct VSInput { - float3 position : POSITION; - float4 color : COLOR0; + float4 position : POSITION; + float4 color : COLOR; }; struct PSInput { - float4 color : COLOR0; + float4 position : SV_POSITION; + float4 color : COLOR; }; PSInput main(VSInput input) { PSInput output; - output.color = float4(1, 1, 1, 1); + input.position.w = 1.0f; + output.position = mul(world, input.position); + output.position = mul(view, output.position); + output.position = mul(proj, output.position); + + output.color = input.color; + return output; } \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index f66e9571b..9a20bfd27 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -50,12 +50,19 @@ const ShaderVertexLayout VertexLayout[] = { { "COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*3 }, }; +struct PSCBuffer +{ + DXMatrix world; + DXMatrix view; + DXMatrix proj; +}; + /** * Implements OnStart(). */ int OnInit() { Ref gfx_ptr = new MTDXDevice(); - Device* gfx = gfx_ptr.Ptr(); + Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); @@ -64,20 +71,20 @@ int OnInit() { Vertex vertices[]= { { - {-0.5, -0.5, 0.5}, - { 1, 0, 0, 1}, + {-0.5, -0.5, 0.0}, + { 1.0, 0.0, 0.0, 1.0}, }, { - {-0.5, 0.5, 0.5}, - {0, 1, 0, 1}, + {-0.5, 0.5, 0.0}, + { 0.0, 0.1, 0.0, 1.0}, }, { - {0.5, 0.5, 0.5}, - {0, 0, 1, 1}, + { 0.5, 0.5, 0.0}, + { 0.0, 0.0, 1.0, 1.0}, }, { - {0.5, -0.5, 0.5}, - {0, 0, 1, 1}, + { 0.5, -0.5, 0.0}, + { 0.5, 0.5, 1.0, 1.0}, } }; @@ -99,8 +106,23 @@ int OnInit() { gfx.Begin(_rand_color); - gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); + PSCBuffer psCBuffer; + + DXMatrixIdentity(psCBuffer.world); + DXMatrixIdentity(psCBuffer.view); + DXMatrixIdentity(psCBuffer.proj); + DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI/6, 1.5f, 0.1f, 100.0f); + DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -5), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); + DXMatrix rotate; + static float x = 0; x += 0.1f; + DXMatrixRotationZ(rotate, x); + + DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate); + + + _shader_v.Ptr().SetCBuffer(psCBuffer); + gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); gfx.Render(_vbuff.Ptr(), _ibuff.Ptr()); gfx.End(); From 792b64f5d81502745a279a47a20c5b3e28011dda Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 27 Apr 2021 17:16:39 +0200 Subject: [PATCH 16/97] Working 3D renderer with Cube class and custom `Mesh`-es support. --- 3D/Cube.h | 67 + 3D/Device.h | 86 +- 3D/Devices/MTDX/MTDXDevice.h | 53 +- 3D/Devices/MTDX/MTDXIndexBuffer.h | 47 +- 3D/Devices/MTDX/MTDXShader.h | 109 +- 3D/Devices/MTDX/MTDXVertexBuffer.h | 44 +- 3D/Face.h | 92 + 3D/Frontend.h | 31 +- 3D/Frontends/MT5Frontend.h | 91 +- 3D/IndexBuffer.h | 31 +- 3D/Math.h | 3211 ++++++++++++++++++++++++++++ 3D/Mesh.h | 172 ++ 3D/Shader.h | 45 +- 3D/VertexBuffer.h | 30 +- Dict.mqh | 14 + DictObject.mqh | 14 + DictStruct.mqh | 14 + Util.h | 46 + tests/3DTest.mq5 | 115 +- 19 files changed, 4138 insertions(+), 174 deletions(-) create mode 100644 3D/Cube.h create mode 100644 3D/Face.h create mode 100644 3D/Math.h create mode 100644 3D/Mesh.h create mode 100644 Util.h diff --git a/3D/Cube.h b/3D/Cube.h new file mode 100644 index 000000000..b11194300 --- /dev/null +++ b/3D/Cube.h @@ -0,0 +1,67 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Cube mesh. + */ + +#include "Face.h" +#include "Mesh.h" + +/** + * Cube mesh. + */ +template +class Cube : public Mesh { + public: + Cube(float x = 0.0f, float y = 0.0f, float z = 0.0f, float size_x = 1.0f, float size_y = 1.0f, float size_z = 1.0f) { + float half_x = size_x / 2; + float half_y = size_y / 2; + float half_z = size_z / 2; + + Face f1(x - half_x, y - half_y, z - half_z, x - half_x, y + half_y, z - half_z, x + half_x, y + half_y, + z - half_z, x + half_x, y - half_y, z - half_z); + + Face f2(x + half_x, y - half_y, z + half_z, x + half_x, y + half_y, z + half_z, x - half_x, y + half_y, + z + half_z, x - half_x, y - half_y, z + half_z); + + Face f3(x - half_x, y - half_y, z + half_z, x - half_x, y + half_y, z + half_z, x - half_x, y + half_y, + z - half_z, x - half_x, y - half_y, z - half_z); + + Face f4(x + half_x, y - half_y, z - half_z, x + half_x, y + half_y, z - half_z, x + half_x, y + half_y, + z + half_z, x + half_x, y - half_y, z + half_z); + + Face f5(x - half_x, y - half_y, z + half_z, x - half_x, y - half_y, z - half_z, x + half_x, y - half_y, + z - half_z, x + half_x, y - half_y, z + half_z); + + Face f6(x - half_x, y + half_y, z - half_z, x - half_x, y + half_y, z + half_z, x + half_x, y + half_y, + z + half_z, x + half_x, y + half_y, z - half_z); + + AddFace(f1); + AddFace(f2); + AddFace(f3); + AddFace(f4); + AddFace(f5); + AddFace(f6); + } +}; \ No newline at end of file diff --git a/3D/Device.h b/3D/Device.h index 71a952b58..e9b259e0a 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -1,9 +1,37 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics device. + */ + #include "../Refs.mqh" #include "Frontend.h" #include "IndexBuffer.h" +#include "Math.h" +#include "Mesh.h" #include "Shader.h" #include "VertexBuffer.h" -#include "Math.h" enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; @@ -11,18 +39,22 @@ enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH } * Graphics device. */ class Device : public Dynamic { -protected: - + protected: int context; - Ref frontend; - + Ref frontend; + public: - + /** + * Initializes graphics device. + */ bool Start(Frontend* _frontend) { frontend = _frontend; return Init(_frontend); } + /** + * Begins render loop. + */ Device* Begin(unsigned int clear_color = 0) { frontend.Ptr().RenderBegin(context); ClearDepth(); @@ -31,27 +63,39 @@ class Device : public Dynamic { return &this; } + /** + * Ends render loop. + */ Device* End() { RenderEnd(); frontend.Ptr().RenderEnd(context); return &this; } + /** + * Deinitializes graphics device. + */ Device* Stop() { Deinit(); return &this; } + /** + * Clears scene's color buffer. + */ Device* Clear(unsigned int _color = 0xFF000000) { ClearBuffer(CLEAR_BUFFER_TYPE_COLOR, _color); return &this; } + /** + * Begins scene's depth buffer. + */ Device* ClearDepth() { ClearBuffer(CLEAR_BUFFER_TYPE_DEPTH, 0); return &this; } - + /** * Returns graphics device context as integer. */ @@ -71,7 +115,7 @@ class Device : public Dynamic { /** * Creates vertex buffer to be used by current graphics device. */ - template + template VertexBuffer* VertexBuffer(T& data[]) { VertexBuffer* _buff = VertexBuffer(); // Unfortunately we can't make this method virtual. @@ -79,8 +123,7 @@ class Device : public Dynamic { // MT5's DirectX. Print("Filling vertex buffer via MTDXVertexBuffer"); ((MTDXVertexBuffer*)_buff).Fill(data); - } - else { + } else { Alert("Unsupported vertex buffer device target"); } return _buff; @@ -95,29 +138,38 @@ class Device : public Dynamic { * Creates index buffer to be used by current graphics device. */ virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL; - + /** * Renders vertex buffer with optional point indices. */ virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; - + /** - * Activates shader for rendering. + * Renders given mesh. */ - void SetShader(Shader *_shader) { - _shader.Select(); + template + void Render(Mesh* _mesh) { + Print("Rendering mesh"); + VertexBuffer* _vertices; + IndexBuffer* _indices; + _mesh.GetBuffers(&this, _vertices, _indices); + Render(_vertices, _indices); } + /** + * Activates shader for rendering. + */ + void SetShader(Shader* _shader) { _shader.Select(); } + /** * Activates shaders for rendering. */ - void SetShader(Shader *_shader1, Shader *_shader2) { + void SetShader(Shader* _shader1, Shader* _shader2) { _shader1.Select(); _shader2.Select(); } protected: - /** * Initializes graphics device. */ diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 1777b485c..5794160c2 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -1,3 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted graphics device. + */ + #include "../../Device.h" class MTDXDevice : public Device { @@ -25,17 +52,13 @@ class MTDXDevice : public Device { /** * Starts rendering loop. */ - virtual bool RenderBegin() { - return true; - } + virtual bool RenderBegin() { return true; } /** * Ends rendering loop. */ - virtual bool RenderEnd() { - return true; - } - + virtual bool RenderEnd() { return true; } + /** * Returns DX context's id. */ @@ -49,7 +72,7 @@ class MTDXDevice : public Device { */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color = 0x000000) { if (_type == CLEAR_BUFFER_TYPE_COLOR) { - DXVector _dx_color; + DXVector _dx_color; _dx_color.x = 1.0f / 255.0f * ((_color & 0x00FF0000) >> 16); _dx_color.y = 1.0f / 255.0f * ((_color & 0x0000FF00) >> 8); _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); @@ -89,10 +112,8 @@ class MTDXDevice : public Device { /** * Creates vertex buffer to be used by current graphics device. */ - VertexBuffer* VertexBuffer() { - return new MTDXVertexBuffer(&this); - } - + VertexBuffer* VertexBuffer() { return new MTDXVertexBuffer(&this); } + /** * Creates index buffer to be used by current graphics device. */ @@ -101,7 +122,10 @@ class MTDXDevice : public Device { _buffer.Fill(_indices); return _buffer; } - + + /** + * + */ virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _vertices.Select(); @@ -110,8 +134,7 @@ class MTDXDevice : public Device { Print("Can't draw!"); } Print("DXDraw: LastError: ", GetLastError()); - } - else { + } else { _indices.Select(); DXDrawIndexed(context); Print("DXDrawIndexed: LastError: ", GetLastError()); diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 6b305c832..ae6d6ff3c 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -1,36 +1,59 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted graphics device's index buffer. + */ + #include "../../IndexBuffer.h" class MTDXIndexBuffer : public IndexBuffer { -public: - + public: MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {} - -protected: - + + protected: int handle; /** * Creates index buffer. */ virtual bool Create(void*& _data[]) { - //handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); + // handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data); return handle != INVALID_HANDLE; } /** * Destructor; - */ - ~MTDXIndexBuffer() { - DXRelease(handle); - } - + */ + ~MTDXIndexBuffer() { DXRelease(handle); } + /** * Fills index buffer with indices. */ virtual void Fill(unsigned int& _indices[]) { handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_INDEX, _indices); } - + /** * Activates index buffer for rendering. */ diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index 957ec122a..1fcf90a68 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -1,21 +1,56 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted unversal graphics shader. + */ + #include "../../Shader.h" class MTDXShader : public Shader { + // DX context handle. int handle; + + // DX C-Buffer handle. int cbuffer_handle; public: - MTDXShader(Device *_device) : Shader(_device) {} + /** + * Constructor. + */ + MTDXShader(Device* _device) : Shader(_device) {} + /** + * Creates a shader. + */ bool Create(ENUM_SHADER_TYPE _type, string _source_code, string _entry_point = "main") { string error_text; - handle = DXShaderCreate(GetDevice().Context(), - _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, - error_text); - + handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, + _source_code, _entry_point, error_text); + Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); - + cbuffer_handle = 0; return true; @@ -24,42 +59,50 @@ class MTDXShader : public Shader { /** * Sets vertex/pixel data layout to be used by shader. */ - virtual void SetDataLayout(const ShaderVertexLayout &_layout[]) { + virtual void SetDataLayout(const ShaderVertexLayout& _layout[]) { // Converting generic layout into MT5 DX's one. - - DXVertexLayout _target_layout[]; + + DXVertexLayout _target_layout[]; ArrayResize(_target_layout, ArraySize(_layout)); - + Print("ArrayResize: LastError: ", GetLastError()); - + int i; - + for (i = 0; i < ArraySize(_layout); ++i) { _target_layout[i].semantic_name = _layout[i].name; _target_layout[i].semantic_index = _layout[i].index; _target_layout[i].format = ParseFormat(_layout[i]); } - + for (i = 0; i < ArraySize(_target_layout); ++i) { - Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", EnumToString(_target_layout[i].format)); + Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", + EnumToString(_target_layout[i].format)); } - + Print("before DXShaderSetLayout: LastError: ", GetLastError()); - + DXShaderSetLayout(handle, _target_layout); - + Print("DXShaderSetLayout: LastError: ", GetLastError()); - + ResetLastError(); } - + + /** + * Converts vertex layout's item into required DX's color format. + */ ENUM_DX_FORMAT ParseFormat(const ShaderVertexLayout& _layout) { if (_layout.type == GFX_VAR_TYPE_FLOAT) { switch (_layout.num_components) { - case 1: return DX_FORMAT_R32_FLOAT; - case 2: return DX_FORMAT_R32G32_FLOAT; - case 3: return DX_FORMAT_R32G32B32_FLOAT; - case 4: return DX_FORMAT_R32G32B32A32_FLOAT; + case 1: + return DX_FORMAT_R32_FLOAT; + case 2: + return DX_FORMAT_R32G32_FLOAT; + case 3: + return DX_FORMAT_R32G32B32_FLOAT; + case 4: + return DX_FORMAT_R32G32B32A32_FLOAT; default: Alert("Too many components in vertex layout!"); } @@ -68,8 +111,11 @@ class MTDXShader : public Shader { Alert("Wrong vertex layout!"); return (ENUM_DX_FORMAT)0; } - - template + + /** + * Sets custom input buffer for shader. + */ + template void SetCBuffer(const X& data) { if (cbuffer_handle == 0) { cbuffer_handle = DXInputCreate(GetDevice().Context(), sizeof(X)); @@ -77,16 +123,17 @@ class MTDXShader : public Shader { int _input_handles[1]; _input_handles[0] = cbuffer_handle; - + DXShaderInputsSet(handle, _input_handles); Print("DXShaderInputsSet: LastError: ", GetLastError()); } - + DXInputSet(cbuffer_handle, data); Print("DXInputSet: LastError: ", GetLastError()); } - - virtual void Select() { - DXShaderSet(GetDevice().Context(), handle); - } + + /** + * Selectes shader to be used by graphics device for rendering. + */ + virtual void Select() { DXShaderSet(GetDevice().Context(), handle); } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index afb844e15..c3cf7fdda 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -1,30 +1,54 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MetaTrader DX-targeted graphics vertex buffer. + */ + #include "../../VertexBuffer.h" class MTDXVertexBuffer : public VertexBuffer { - int handle; public: - - MTDXVertexBuffer(Device *_device) : VertexBuffer(_device) {} - + MTDXVertexBuffer(Device* _device) : VertexBuffer(_device) {} + ~MTDXVertexBuffer() { - DXRelease(handle); + // DXRelease(handle); } - -public: - + + public: /** * Creates vertex buffer. */ - template + template bool Fill(X& _data[]) { handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_VERTEX, _data); Print("Created vb ", handle); Print("Fill: LastError: ", GetLastError()); return true; } - + virtual void Select() { Print("Selecting vb ", handle); DXBufferSet(GetDevice().Context(), handle); diff --git a/3D/Face.h b/3D/Face.h new file mode 100644 index 000000000..c8a8ee9c9 --- /dev/null +++ b/3D/Face.h @@ -0,0 +1,92 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics face object. + */ + +#include "Math.h" + +// Face flags. +enum ENUM_FACE_FLAGS { FACE_FLAGS_NONE, FACE_FLAGS_TRIANGLE, FACE_FLAGS_QUAD }; + +// Face (3 or 4 vertices). +template +struct Face { + // Flags. + ENUM_FACE_FLAGS flags; + + // 3 or 4 points. + T points[4]; + + /** + * Constructor. + */ + Face() { flags = FACE_FLAGS_NONE; } + + /** + * Copy constructor. + */ + Face(const Face& r) { + flags = r.flags; + for (int p = 0; p < 4; ++p) { + points[p] = r.points[p]; + } + } + + /** + * Constructor. + */ + Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) { + flags = FACE_FLAGS_TRIANGLE; + points[0].Position[0] = x1; + points[0].Position[1] = y1; + points[0].Position[2] = z1; + points[1].Position[0] = x2; + points[1].Position[1] = y2; + points[1].Position[2] = z2; + points[2].Position[0] = x3; + points[2].Position[1] = y3; + points[2].Position[2] = z3; + } + + /** + * Constructor. + */ + Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, + float z4) { + flags = FACE_FLAGS_QUAD; + points[0].Position[0] = x1; + points[0].Position[1] = y1; + points[0].Position[2] = z1; + points[1].Position[0] = x2; + points[1].Position[1] = y2; + points[1].Position[2] = z2; + points[2].Position[0] = x3; + points[2].Position[1] = y3; + points[2].Position[2] = z3; + points[3].Position[0] = x4; + points[3].Position[1] = y4; + points[3].Position[2] = z4; + } +}; \ No newline at end of file diff --git a/3D/Frontend.h b/3D/Frontend.h index e0696eaa9..6edbec4bf 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -1,3 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics front-end (display buffer target). + */ + #include "../Refs.mqh" /** @@ -29,13 +56,11 @@ class Frontend : public Dynamic { * Executed before render starts. */ virtual void RenderBegin(int context) = NULL; - + /** * Executed after render ends. */ virtual void RenderEnd(int context) = NULL; - - virtual void Refresh(int context) {}; /** * Returns canvas' width. diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index ef0caa6d2..3d75592ec 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -1,30 +1,66 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * MT5 graphics front-end (display buffer target). + */ + #include "../Frontend.h" /** * MetaTrader 5 chart target. */ class MT5Frontend : public Frontend { + // Target image pixel buffer. unsigned int image[]; + + // Previous size of the window. int last_width, last_height; + + // Target image's resource name. string resname; + + // Target image's object name. string objname; - -public: - + + public: + /** + * Initializes canvas. + */ virtual bool Init() { // Hiding 2D chart. ChartSetInteger(0, CHART_SHOW, false); ChartRedraw(); - + Print("LastError: ", GetLastError()); - + objname = "MT5_Frontend_" + IntegerToString(ChartID()); - resname = "::MT5_Frontend" + IntegerToString(ChartID()); + resname = "::MT5_Frontend" + IntegerToString(ChartID()); ObjectCreate(0, objname, OBJ_BITMAP_LABEL, 0, 0, 0); ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 0); ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 0); Print("LastError: ", GetLastError()); - + Print("LastError: ", GetLastError()); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); ObjectSetString(ChartID(), objname, OBJPROP_BMPFILE, resname); @@ -32,40 +68,52 @@ class MT5Frontend : public Frontend { return true; } + /** + * Deinitializes canvas. + */ virtual bool Deinit() { ResourceFree(resname); ObjectDelete(0, objname); ChartSetInteger(0, CHART_SHOW, true); return true; } - + + /** + * Resizes target image buffer if needed. + */ bool Resize() { if (Width() == last_width && Height() == last_height) { return false; } - + ArrayResize(image, Width() * Height()); Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); - ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); Print("ResourceCreate: LastError: ", GetLastError()); - + last_width = Width(); - last_height = Height(); - + last_height = Height(); + return true; } - + + /** + * Executed before render starts. + */ virtual void RenderBegin(int context) { Print("MT5Frontend: RenderBegin()"); Print("Image resize: width = ", Width(), ", height = ", Height()); if (Resize()) { DXContextSetSize(context, Width(), Height()); - } - + } + Print("DXContextSetSize: LastError: ", GetLastError()); } - + + /** + * Executed after render ends. + */ virtual void RenderEnd(int context) { Print("MT5Frontend: RenderEnd()"); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); @@ -77,11 +125,14 @@ class MT5Frontend : public Frontend { ChartRedraw(); Sleep(5); } - - virtual void Refresh(int context) { - } + /** + * Returns canvas' width. + */ virtual int Width() { return (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS); } + /** + * Returns canvas' height. + */ virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } }; \ No newline at end of file diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h index 230532002..fef406675 100644 --- a/3D/IndexBuffer.h +++ b/3D/IndexBuffer.h @@ -1,3 +1,30 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics index buffer. + */ + #include "../Refs.mqh" class Device; @@ -23,12 +50,12 @@ class IndexBuffer : public Dynamic { * Creates index buffer. */ virtual bool Create(void*& _data[]) = NULL; - + /** * Fills index buffer with indices. */ virtual void Fill(unsigned int& _indices[]) = NULL; - + /** * Activates index buffer for rendering. */ diff --git a/3D/Math.h b/3D/Math.h new file mode 100644 index 000000000..f4ca30204 --- /dev/null +++ b/3D/Math.h @@ -0,0 +1,3211 @@ +//+------------------------------------------------------------------+ +//| DXMath.mqh | +//| Copyright 2019,MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2019,MetaQuotes Software Corp." +#property link "https://www.mql5.com" +//+------------------------------------------------------------------+ +//| DirectX Math Routines | +//+------------------------------------------------------------------+ +//| Ported from C++ code of ReactOS, written by David Adam | +//| and Tony Wasserka | +//| | +//| https://doxygen.reactos.org/de/d57/ | +//| dll_2directx_2wine_2d3dx9__36_2math_8c_source.html | +//| | +//| Copyright (C) 2007 David Adam | +//| Copyright (C) 2007 Tony Wasserka | +//+------------------------------------------------------------------+ +#define DX_PI 3.1415926535897932384626f +#define DX_PI_DIV2 1.5707963267948966192313f +#define DX_PI_DIV3 1.0471975511965977461542f +#define DX_PI_DIV4 0.7853981633974483096156f +#define DX_PI_DIV6 0.5235987755982988730771f +#define DX_PI_MUL2 6.2831853071795864769253f +#define DXSH_MINORDER 2 +#define DXSH_MAXORDER 6 +//+------------------------------------------------------------------+ +//| Preliminary declarations | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| DXColor | +//+------------------------------------------------------------------+ +struct DXColor; +struct DXPlane; +struct DXVector2; +struct DXVector3; +struct DXVector4; +struct DXMatrix; +struct DXQuaternion; +struct DViewport; +//+------------------------------------------------------------------+ +//| DXColor | +//+------------------------------------------------------------------+ +struct DXColor { + float r; + float g; + float b; + float a; + //--- constructors + DXColor(void) { + r = 0.0; + g = 0.0; + b = 0.0; + a = 1.0; + } + DXColor(float red, float green, float blue, float alpha) { + r = red; + g = green; + b = blue; + a = alpha; + } + DXColor(const DXVector4 &v) { + r = v.x; + g = v.y; + b = v.z; + a = v.w; + } + DXColor(const DXVector3 &v) { + r = v.x; + g = v.y; + b = v.z; + a = 1.0; + } +}; +//+------------------------------------------------------------------+ +//| DXPlane | +//+------------------------------------------------------------------+ +struct DXPlane { + float a; + float b; + float c; + float d; +}; +//+------------------------------------------------------------------+ +//| DXVector2 | +//+------------------------------------------------------------------+ +struct DXVector2 { + float x; + float y; + //--- constructors + DXVector2(void) { + x = 0.0; + y = 0.0; + } + DXVector2(float v) { + x = v; + y = v; + } + DXVector2(float vx, float vy) { + x = vx; + y = vy; + } + DXVector2(const DXVector3 &v) { + x = v.x; + y = v.y; + } + DXVector2(const DXVector4 &v) { + x = v.x; + y = v.y; + } +}; +//+------------------------------------------------------------------+ +//| DXVector3 | +//+------------------------------------------------------------------+ +struct DXVector3 { + float x; + float y; + float z; + //--- constructors + DXVector3(void) { + x = 0.0; + y = 0.0; + z = 0.0; + } + DXVector3(float v) { + x = v; + y = v; + z = v; + } + DXVector3(float vx, float vy, float vz) { + x = vx; + y = vy; + z = vz; + } + DXVector3(const DXVector2 &v) { + x = v.x; + y = v.y; + z = 0.0; + } + DXVector3(const DXVector4 &v) { + x = v.x; + y = v.y; + z = v.z; + } +}; +//+------------------------------------------------------------------+ +//| DXVector4 | +//+------------------------------------------------------------------+ +struct DXVector4 { + float x; + float y; + float z; + float w; + //--- constructors + DXVector4(void) { + x = 0.0; + y = 0.0; + z = 0.0; + w = 1.0; + } + DXVector4(float v) { + x = v; + y = v; + z = v; + w = v; + } + DXVector4(float vx, float vy, float vz, float vw) { + x = vx; + y = vy; + z = vz; + w = vw; + } + DXVector4(const DXVector2 &v) { + x = v.x; + y = v.y; + z = 0.0; + w = 1.0; + } + DXVector4(const DXVector3 &v) { + x = v.x; + y = v.y; + z = v.z; + w = 1.0; + } +}; +//+------------------------------------------------------------------+ +//| DXMatrix | +//+------------------------------------------------------------------+ +struct DXMatrix { + float m[4][4]; +}; +//+------------------------------------------------------------------+ +//| DXQuaternion | +//+------------------------------------------------------------------+ +struct DXQuaternion { + float x; + float y; + float z; + float w; +}; +//+------------------------------------------------------------------+ +//| DViewport | +//+------------------------------------------------------------------+ +struct DViewport { + ulong x; + ulong y; + ulong width; + ulong height; + float minz; + float maxz; +}; + +/* +//--- DXColor functions +void DXColorAdd(DXColor &pout,const DXColor &pc1,const DXColor &pc2); +void DXColorAdjustContrast(DXColor &pout,const DXColor &pc,float s); +void DXColorAdjustSaturation(DXColor &pout,const DXColor &pc,float s); +void DXColorLerp(DXColor &pout,const DXColor &pc1,const DXColor &pc2,float s); +void DXColorModulate(DXColor &pout,const DXColor &pc1,const DXColor &pc2); +void DXColorNegative(DXColor &pout,const DXColor &pc); +void DXColorScale(DXColor &pout,const DXColor &pc,float s); +void DXColorSubtract(DXColor &pout,const DXColor &pc1,const DXColor &pc2); +float DXFresnelTerm(float costheta,float refractionindex); + +//--- DXVector2 functions +void DXVec2Add(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2BaryCentric(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2,const DXVector2 &pv3,float f,float g); +void DXVec2CatmullRom(DXVector2 &pout,const DXVector2 &pv0,const DXVector2 &pv1,const DXVector2 &pv2,const DXVector2 +&pv3,float s); float DXVec2CCW(const DXVector2 &pv1,const DXVector2 &pv2); float DXVec2Dot(const DXVector2 &pv1,const +DXVector2 &pv2); void DXVec2Hermite(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pt1,const DXVector2 +&pv2,const DXVector2 &pt2,float s); float DXVec2Length(const DXVector2 &v); float DXVec2LengthSq(const DXVector2 &v); +void DXVec2Lerp(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2,float s); +void DXVec2Maximize(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2Minimize(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2Normalize(DXVector2 &pout,const DXVector2 &pv); +void DXVec2Scale(DXVector2 &pout,const DXVector2 &pv,float s); +void DXVec2Subtract(DXVector2 &pout,const DXVector2 &pv1,const DXVector2 &pv2); +void DXVec2Transform(DXVector4 &pout,const DXVector2 &pv,const DXMatrix &pm); +void DXVec2TransformCoord(DXVector2 &pout,const DXVector2 &pv,const DXMatrix &pm); +void DXVec2TransformNormal(DXVector2 &pout,const DXVector2 &pv,const DXMatrix &pm); + +//--- DXVector3 functions +void DXVec3Add(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); +void DXVec3BaryCentric(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 &pv3,float f,float g); +void DXVec3CatmullRom(DXVector3 &pout,const DXVector3 &pv0,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 +&pv3,float s); void DXVec3Cross(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); float DXVec3Dot(const +DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Hermite(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 +&pt1,const DXVector3 &pv2,const DXVector3 &pt2,float s); float DXVec3Length(const DXVector3 &pv); float +DXVec3LengthSq(const DXVector3 &pv); void DXVec3Lerp(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2,float +s); void DXVec3Maximize(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Minimize(DXVector3 +&pout,const DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Normalize(DXVector3 &pout,const DXVector3 &pv); void +DXVec3Project(DXVector3 &pout,const DXVector3 &pv,const DViewport &pviewport,const DXMatrix &pprojection,const DXMatrix +&pview,const DXMatrix &pworld); void DXVec3Scale(DXVector3 &pout,const DXVector3 &pv,float s); void +DXVec3Subtract(DXVector3 &pout,const DXVector3 &pv1,const DXVector3 &pv2); void DXVec3Transform(DXVector4 &pout,const +DXVector3 &pv,const DXMatrix &pm); void DXVec3TransformCoord(DXVector3 &pout,const DXVector3 &pv,const DXMatrix &pm); +void DXVec3TransformNormal(DXVector3 &pout,const DXVector3 &pv,const DXMatrix &pm); +void DXVec3Unproject(DXVector3 &out,const DXVector3 &v,const DViewport &viewport,const DXMatrix &projection,const +DXMatrix &view,const DXMatrix &world); + +//--- DXVector4 vector functions +void DXVec4Add(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2); +void DXVec4BaryCentric(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2,const DXVector4 &pv3,float f,float g); +void DXVec4CatmullRom(DXVector4 &pout,const DXVector4 &pv0,const DXVector4 &pv1,const DXVector4 &pv2,const DXVector4 +&pv3,float s); void DXVec4Cross(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2,const DXVector4 &pv3); float +DXVec4Dot(const DXVector4 &pv1,const DXVector4 &pv2); void DXVec4Hermite(DXVector4 &pout,const DXVector4 &pv1,const +DXVector4 &pt1,const DXVector4 &pv2,const DXVector4 &pt2,float s); float DXVec4Length(const DXVector4 &pv); float +DXVec4LengthSq(const DXVector4 &pv); void DXVec4Lerp(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2,float +s); void DXVec4Maximize(DXVector4 &pout,const DXVector4 &pv1,const DXVector4 &pv2); void DXVec4Minimize(DXVector4 +&pout,const DXVector4 &pv1,const DXVector4 &pv2); void DXVec4Normalize(DXVector4 &pout,const DXVector4 &pv); void +DXVec4Scale(DXVector4 &pout,const DXVector4 &pv,float s); void DXVec4Subtract(DXVector4 &pout,const DXVector4 +&pv1,const DXVector4 &pv2); void DXVec4Transform(DXVector4 &pout,const DXVector4 &pv,const DXMatrix &pm); + +//---DXQuaternion functions +void DXQuaternionBaryCentric(DXQuaternion &pout,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3,float f,float g); +void DXQuaternionConjugate(DXQuaternion &pout,const DXQuaternion &pq); +float DXQuaternionDot(DXQuaternion &a,DXQuaternion &b); +void DXQuaternionExp(DXQuaternion &out,const DXQuaternion &q); +void DXQuaternionIdentity(DXQuaternion &out); +bool DXQuaternionIsIdentity(DXQuaternion &pq); +float DXQuaternionLength(const DXQuaternion &pq); +float DXQuaternionLengthSq(const DXQuaternion &pq); +void DXQuaternionInverse(DXQuaternion &pout,const DXQuaternion &pq); +void DXQuaternionLn(DXQuaternion &out,const DXQuaternion &q); +void DXQuaternionMultiply(DXQuaternion &pout,const DXQuaternion &pq1,const DXQuaternion &pq2); +void DXQuaternionNormalize(DXQuaternion &out,const DXQuaternion &q); +void DXQuaternionRotationAxis(DXQuaternion &out,const DXVector3 &v,float angle); +void DXQuaternionRotationMatrix(DXQuaternion &out,const DXMatrix &m); +void DXQuaternionRotationYawPitchRoll(DXQuaternion &out,float yaw,float pitch,float roll); +void DXQuaternionSlerp(DXQuaternion &out,DXQuaternion &q1,DXQuaternion &q2,float t); +void DXQuaternionSquad(DXQuaternion &pout,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3,DXQuaternion &pq4,float +t); void DXQuaternionSquadSetup(DXQuaternion &paout,DXQuaternion &pbout,DXQuaternion &pcout,DXQuaternion +&pq0,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3); void DXQuaternionToAxisAngle(const DXQuaternion +&pq,DXVector3 &paxis,float &pangle); DXQuaternion add_diff(const DXQuaternion &q1,const DXQuaternion &q2,const float +add); + +//--- DXMatrix functions +void DXMatrixIdentity(DXMatrix &out); +bool DXMatrixIsIdentity(DXMatrix &pm); +void DXMatrixAffineTransformation(DXMatrix &out,float scaling,const DXVector3 &rotationcenter,const DXQuaternion +&rotation,const DXVector3 &translation); void DXMatrixAffineTransformation2D(DXMatrix &out,float scaling,const +DXVector2 &rotationcenter,float rotation,const DXVector2 &translation); int DXMatrixDecompose(DXVector3 +&poutscale,DXQuaternion &poutrotation,DXVector3 &pouttranslation,const DXMatrix &pm); float DXMatrixDeterminant(const +DXMatrix &pm); void DXMatrixInverse(DXMatrix &pout,float &pdeterminant,const DXMatrix &pm); void +DXMatrixLookAtLH(DXMatrix &out,const DXVector3 &eye,const DXVector3 &at,const DXVector3 &up); void +DXMatrixLookAtRH(DXMatrix &out,const DXVector3 &eye,const DXVector3 &at,const DXVector3 &up); void +DXMatrixMultiply(DXMatrix &pout,const DXMatrix &pm1,const DXMatrix &pm2); void DXMatrixMultiplyTranspose(DXMatrix +&pout,const DXMatrix &pm1,const DXMatrix &pm2); void DXMatrixOrthoLH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixOrthoOffCenterLH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixOrthoOffCenterRH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixOrthoRH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixPerspectiveFovLH(DXMatrix &pout,float fovy,float aspect,float zn,float zf); +void DXMatrixPerspectiveFovRH(DXMatrix &pout,float fovy,float aspect,float zn,float zf); +void DXMatrixPerspectiveLH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf); +void DXMatrixPerspectiveRH(DXMatrix &pout,float w,float h,float zn,float zf); +void DXMatrixReflect(DXMatrix &pout,const DXPlane &pplane); +void DXMatrixRotationAxis(DXMatrix &out,const DXVector3 &v,float angle); +void DXMatrixRotationQuaternion(DXMatrix &pout,const DXQuaternion &pq); +void DXMatrixRotationX(DXMatrix &pout,float angle); +void DXMatrixRotationY(DXMatrix &pout,float angle); +void DXMatrixRotationYawPitchRoll(DXMatrix &out,float yaw,float pitch,float roll); +void DXMatrixRotationZ(DXMatrix &pout,float angle); +void DXMatrixScaling(DXMatrix &pout,float sx,float sy,float sz); +void DXMatrixShadow(DXMatrix &pout,const DXVector4 &plight,const DXPlane &pplane); +void DXMatrixTransformation(DXMatrix &pout,const DXVector3 &pscalingcenter,const DXQuaternion &pscalingrotation,const +DXVector3 &pscaling,const DXVector3 &protationcenter,const DXQuaternion &protation,const DXVector3 &ptranslation); void +DXMatrixTransformation2D(DXMatrix &pout,const DXVector2 &pscalingcenter,float scalingrotation,const DXVector2 +&pscaling,const DXVector2 &protationcenter,float rotation,const DXVector2 &ptranslation); void +DXMatrixTranslation(DXMatrix &pout,float x,float y,float z); void DXMatrixTranspose(DXMatrix &pout,const DXMatrix &pm); + +//--- DXPlane functions | +float DXPlaneDot(const DXPlane &p1,const DXVector4 &p2); +float DXPlaneDotCoord(const DXPlane &pp,const DXVector4 &pv); +float DXPlaneDotNormal(const DXPlane &pp,const DXVector4 &pv); +void DXPlaneFromPointNormal(DXPlane &pout,const DXVector3 &pvpoint,const DXVector3 &pvnormal); +void DXPlaneFromPoints(DXPlane &pout,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 &pv3); +void DXPlaneIntersectLine(DXVector3 &pout,const DXPlane &pp,const DXVector3 &pv1,const DXVector3 &pv2); +void DXPlaneNormalize(DXPlane &out,const DXPlane &p); +void DXPlaneScale(DXPlane &pout,const DXPlane &p,float s); +void DXPlaneTransform(DXPlane &pout,const DXPlane &pplane,const DXMatrix &pm); + +//---- spherical harmonic functions +void DXSHAdd(float &out[],int order,const float &a[],const float &b[]); +float DXSHDot(int order,const float &a[],const float &b[]); +int DXSHEvalConeLight(int order,const DXVector3 &dir,float radius,float Rintensity,float Gintensity,float +Bintensity,float &rout[],float &gout[],float &bout[]); void DXSHEvalDirection(float &out[],int order,const DXVector3 +&dir); int DXSHEvalDirectionalLight(int order,const DXVector3 &dir,float Rintensity,float Gintensity,float +Bintensity,float &rout[],float &gout[],float &bout[]); int DXSHEvalHemisphereLight(int order,const DXVector3 +&dir,DXColor &top,DXColor &bottom,float &rout[],float &gout[],float &bout[]); int DXSHEvalSphericalLight(int +order,const DXVector3 &dir,float radius,float Rintensity,float Gintensity,float Bintensity,float &rout[],float +&gout[],float &bout[]); void DXSHMultiply2(float &out[],const float &a[],const float &b[]); void DXSHMultiply3(float +&out[],const float &a[],const float &b[]); void DXSHMultiply4(float &out[],const float &a[],const float &b[]); void +DXSHRotate(float &out[],int order,const DXMatrix &matrix,const float &in[]); void DXSHRotateZ(float &out[],int +order,float angle,const float &in[]); void DXSHScale(float &out[],int order,const float &a[],const float scale); + +//--- scalar functions +float DXScalarLerp(const float val1,const float val2,float s) +float DXScalarBiasScale(const float val,const float bias,const float scale) +*/ + +//+------------------------------------------------------------------+ +//| Adds two color values together to create a new color value. | +//+------------------------------------------------------------------+ +void DXColorAdd(DXColor &pout, const DXColor &pc1, const DXColor &pc2) { + pout.r = pc1.r + pc2.r; + pout.g = pc1.g + pc2.g; + pout.b = pc1.b + pc2.b; + pout.a = pc1.a + pc2.a; +} +//+------------------------------------------------------------------+ +//| Adjusts the contrast value of a color. | +//+------------------------------------------------------------------+ +//| The input alpha channel is copied, unmodified, | +//| to the output alpha channel. | +//| | +//| This function interpolates the red,green,and blue color | +//| components of a DXColor structure between fifty percent gray | +//| and a specified contrast value,as shown in the following example.| +//| | +//| pout.r = 0.5f + s*(pc.r - 0.5f); | +//| | +//| If s is greater than 0 and less than 1,the contrast is decreased.| +//| If s is greater than 1, the contrast is increased. | +//+------------------------------------------------------------------+ +void DXColorAdjustContrast(DXColor &pout, const DXColor &pc, float s) { + pout.r = 0.5f + s * (pc.r - 0.5f); + pout.g = 0.5f + s * (pc.g - 0.5f); + pout.b = 0.5f + s * (pc.b - 0.5f); + pout.a = pc.a; +} +//+------------------------------------------------------------------+ +//| Adjusts the saturation value of a color. | +//+------------------------------------------------------------------+ +//| The input alpha channel is copied, unmodified, | +//| to the output alpha channel. | +//| | +//| This function interpolates the red, green, and blue color | +//| components of a DXColor structure between an unsaturated color | +//| and a color, as shown in the following example. | +//| | +//| Approximate values for each component's contribution to | +//| luminance. Based upon the NTSC standard described in | +//| ITU-R Recommendation BT.709. | +//| float grey = pc.r*0.2125f + pc.g*0.7154f + pc.b*0.0721f; | +//| | +//| pout.r = grey + s*(pc.r - grey); | +//| If s is greater than 0 and less than 1, the saturation is | +//| decreased. If s is greater than 1, the saturation is increased. | +//| | +//| The grayscale color is computed as: | +//| r = g = b = 0.2125*r + 0.7154*g + 0.0721*b | +//+------------------------------------------------------------------+ +void DXColorAdjustSaturation(DXColor &pout, const DXColor &pc, float s) { + float grey = pc.r * 0.2125f + pc.g * 0.7154f + pc.b * 0.0721f; + pout.r = grey + s * (pc.r - grey); + pout.g = grey + s * (pc.g - grey); + pout.b = grey + s * (pc.b - grey); + pout.a = pc.a; +} +//+------------------------------------------------------------------+ +//| Uses linear interpolation to create a color value. | +//+------------------------------------------------------------------+ +//| This function interpolates the red, green, blue, and alpha | +//| components of a DXColor structure between two colors, as shown | +//| in the following example. | +//| | +//| pout.r = pC1.r + s * (pC2.r - pC1.r); | +//| | +//| If you are linearly interpolating between the colors A and B, | +//| and s is 0, the resulting color is A. | +//| If s is 1, the resulting color is color B. | +//+------------------------------------------------------------------+ +void DXColorLerp(DXColor &pout, const DXColor &pc1, const DXColor &pc2, float s) { + pout.r = (1 - s) * pc1.r + s * pc2.r; + pout.g = (1 - s) * pc1.g + s * pc2.g; + pout.b = (1 - s) * pc1.b + s * pc2.b; + pout.a = (1 - s) * pc1.a + s * pc2.a; +} +//+------------------------------------------------------------------+ +//| Blends two colors. | +//+------------------------------------------------------------------+ +//| This function blends together two colors by multiplying matching | +//| color components, as shown in the following example. | +//| pout.r = pC1.r * pC2.r; | +//+------------------------------------------------------------------+ +void DXColorModulate(DXColor &pout, const DXColor &pc1, const DXColor &pc2) { + pout.r = pc1.r * pc2.r; + pout.g = pc1.g * pc2.g; + pout.b = pc1.b * pc2.b; + pout.a = pc1.a * pc2.a; +} +//+------------------------------------------------------------------+ +//| Creates the negative color value of a color value. | +//+------------------------------------------------------------------+ +//| The input alpha channel is copied, unmodified, to the output | +//| alpha channel. | +//| This function returns the negative color value by subtracting 1.0| +//| from the color components of the DXColor structure, | +//| as shown in the following example. | +//| pout.r = 1.0f - pc.r; | +//+------------------------------------------------------------------+ +void DXColorNegative(DXColor &pout, const DXColor &pc) { + pout.r = 1.0f - pc.r; + pout.g = 1.0f - pc.g; + pout.b = 1.0f - pc.b; + pout.a = pc.a; +} +//+------------------------------------------------------------------+ +//| Scales a color value. | +//+------------------------------------------------------------------+ +//| This function computes the scaled color value by multiplying | +//| the color components of the DXColor structure by the specified | +//| scale factor, as shown in the following example. | +//| pOut.r = pC.r*s; | +//+------------------------------------------------------------------+ +void DXColorScale(DXColor &pout, const DXColor &pc, float s) { + pout.r = s * pc.r; + pout.g = s * pc.g; + pout.b = s * pc.b; + pout.a = s * pc.a; +} +//+------------------------------------------------------------------+ +//| Subtracts two color values to create a new color value. | +//+------------------------------------------------------------------+ +void DXColorSubtract(DXColor &pout, const DXColor &pc1, const DXColor &pc2) { + pout.r = pc1.r - pc2.r; + pout.g = pc1.g - pc2.g; + pout.b = pc1.b - pc2.b; + pout.a = pc1.a - pc2.a; +} +//+------------------------------------------------------------------+ +//| Calculate the Fresnel term. | +//+------------------------------------------------------------------+ +//| To find the Fresnel term (F): | +//| If A is angle of incidence and B is the angle of refraction, | +//| then | +//| F = 0.5*[tan2(A - B)/tan2(A + B) + sin2(A - B)/sin2(A + B)] | +//| = 0.5*sin2(A - B)/sin2(A + B)*[cos2(A + B)/cos2(A - B) + 1] | +//| | +//| Let r = sina(A)/sin(B) (the relative refractive index) | +//| Let c = cos(A) | +//| Let g = (r2 + c2 - 1)1/2 | +//| | +//| Then,expanding using the trig identities and simplifying, | +//| you get: | +//| F = 0.5*(g + c)2/(g - c)2*([c(g + c)-1]2/[c(g - c) + 1]2 + 1) | +//+------------------------------------------------------------------+ +float DXFresnelTerm(float costheta, float refractionindex) { + float g = (float)sqrt(refractionindex * refractionindex + costheta * costheta - 1.0f); + float a = g + costheta; + float d = g - costheta; + float result = (costheta * a - 1.0f) * (costheta * a - 1.0f) / ((costheta * d + 1.0f) * (costheta * d + 1.0f)) + 1.0f; + result *= 0.5f * d * d / (a * a); + //--- + return (result); +} +//+------------------------------------------------------------------+ +//| Adds two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Add(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = pv1.x + pv2.x; + pout.y = pv1.y + pv2.y; +} +//+------------------------------------------------------------------+ +//| Returns a point in Barycentric coordinates, | +//| using the specified 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2BaryCentric(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2, const DXVector2 &pv3, float f, + float g) { + pout.x = (1.0f - f - g) * (pv1.x) + f * (pv2.x) + g * (pv3.x); + pout.y = (1.0f - f - g) * (pv1.y) + f * (pv2.y) + g * (pv3.y); +} +//+------------------------------------------------------------------+ +//| Performs a Catmull-Rom interpolation, | +//| using the specified 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2CatmullRom(DXVector2 &pout, const DXVector2 &pv0, const DXVector2 &pv1, const DXVector2 &pv2, + const DXVector2 &pv3, float s) { + pout.x = 0.5f * (2.0f * pv1.x + (pv2.x - pv0.x) * s + (2.0f * pv0.x - 5.0f * pv1.x + 4.0f * pv2.x - pv3.x) * s * s + + (pv3.x - 3.0f * pv2.x + 3.0f * pv1.x - pv0.x) * s * s * s); + pout.y = 0.5f * (2.0f * pv1.y + (pv2.y - pv0.y) * s + (2.0f * pv0.y - 5.0f * pv1.y + 4.0f * pv2.y - pv3.y) * s * s + + (pv3.y - 3.0f * pv2.y + 3.0f * pv1.y - pv0.y) * s * s * s); +} +//+------------------------------------------------------------------+ +//| Returns the z-component by taking the cross product | +//| of two 2D vectors. | +//+------------------------------------------------------------------+ +float DXVec2CCW(const DXVector2 &pv1, const DXVector2 &pv2) { return (pv1.x * pv2.y - pv1.y * pv2.x); } +//+------------------------------------------------------------------+ +//| Determines the dot product of two 2D vectors. | +//+------------------------------------------------------------------+ +float DXVec2Dot(const DXVector2 &pv1, const DXVector2 &pv2) { return (pv1.x * pv2.x + pv1.y * pv2.y); } +//+------------------------------------------------------------------+ +//| Performs a Hermite spline interpolation, | +//| using the specified 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Hermite(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pt1, const DXVector2 &pv2, + const DXVector2 &pt2, float s) { + //--- prepare coefficients + float h1 = 2.0f * s * s * s - 3.0f * s * s + 1.0f; + float h2 = s * s * s - 2.0f * s * s + s; + float h3 = -2.0f * s * s * s + 3.0f * s * s; + float h4 = s * s * s - s * s; + //--- calculate interpolated point + pout.x = h1 * pv1.x + h2 * pt1.x + h3 * pv2.x + h4 * pt2.x; + pout.y = h1 * pv1.y + h2 * pt1.y + h3 * pv2.y + h4 * pt2.y; +} +//+------------------------------------------------------------------+ +//| Returns the length of a 2D vector. | +//+------------------------------------------------------------------+ +float DXVec2Length(const DXVector2 &v) { return ((float)sqrt(v.x * v.x + v.y * v.y)); } +//+------------------------------------------------------------------+ +//| Returns the square of the length of a 2D vector. | +//+------------------------------------------------------------------+ +float DXVec2LengthSq(const DXVector2 &v) { return ((float)(v.x * v.x + v.y * v.y)); } +//+------------------------------------------------------------------+ +//| Performs a linear interpolation between two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Lerp(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2, float s) { + pout.x = (1.0f - s) * pv1.x + s * pv2.x; + pout.y = (1.0f - s) * pv1.y + s * pv2.y; +} +//+------------------------------------------------------------------+ +//| Returns a 2D vector that is made up of the largest components | +//| of two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Maximize(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = (float)fmax(pv1.x, pv2.x); + pout.y = (float)fmax(pv1.y, pv2.y); +} +//+------------------------------------------------------------------+ +//| Returns a 2D vector that is made up of the smallest components | +//| of two 2D vectors. | +//+------------------------------------------------------------------+ +void DXVec2Minimize(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = (float)fmin(pv1.x, pv2.x); + pout.y = (float)fmin(pv1.y, pv2.y); +} +//+------------------------------------------------------------------+ +//| Returns the normalized version of a 2D vector. | +//+------------------------------------------------------------------+ +void DXVec2Normalize(DXVector2 &pout, const DXVector2 &pv) { + //--- calculate length + float norm = DXVec2Length(pv); + if (!norm) { + pout.x = 0.0f; + pout.y = 0.0f; + } else { + pout.x = pv.x / norm; + pout.y = pv.y / norm; + } +} +//+------------------------------------------------------------------+ +//| Scales a 2D vector. | +//+------------------------------------------------------------------+ +void DXVec2Scale(DXVector2 &pout, const DXVector2 &pv, float s) { + pout.x = s * pv.x; + pout.y = s * pv.y; +} +//+------------------------------------------------------------------+ +//| DXVec3Subtract | +//+------------------------------------------------------------------+ +void DXVec2Subtract(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) { + pout.x = pv1.x - pv2.x; + pout.y = pv1.y - pv2.y; +} +//+------------------------------------------------------------------+ +//| Transforms a 2D vector by a given matrix. | +//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//+------------------------------------------------------------------+ +void DXVec2Transform(DXVector4 &pout, const DXVector2 &pv, const DXMatrix &pm) { + DXVector4 out; + out.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[3][0]; + out.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[3][1]; + out.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[3][2]; + out.w = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[3][3]; + pout = out; +} +//+------------------------------------------------------------------+ +//| Transforms a 2D vector by a given matrix, | +//| projecting the result back into w = 1. | +//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//+------------------------------------------------------------------+ +void DXVec2TransformCoord(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { + float norm = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[3][3]; + if (norm) { + pout.x = (pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[3][0]) / norm; + pout.y = (pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[3][1]) / norm; + } else { + pout.x = 0.0f; + pout.y = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Transforms the 2D vector normal by the given matrix. | +//+------------------------------------------------------------------+ +void DXVec2TransformNormal(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { + pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y; + pout.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y; +} +//+------------------------------------------------------------------+ +//| Adds two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Add(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = pv1.x + pv2.x; + pout.y = pv1.y + pv2.y; + pout.z = pv1.z + pv2.z; +} +//+------------------------------------------------------------------+ +//| Returns a point in Barycentric coordinates, | +//| using the specified 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3BaryCentric(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2, const DXVector3 &pv3, float f, + float g) { + pout.x = (1.0f - f - g) * pv1.x + f * pv2.x + g * pv3.x; + pout.y = (1.0f - f - g) * pv1.y + f * pv2.y + g * pv3.y; + pout.z = (1.0f - f - g) * pv1.z + f * pv2.z + g * pv3.z; +} +//+------------------------------------------------------------------+ +//| Performs a Catmull-Rom interpolation, | +//| using the specified 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3CatmullRom(DXVector3 &pout, const DXVector3 &pv0, const DXVector3 &pv1, const DXVector3 &pv2, + const DXVector3 &pv3, float s) { + pout.x = 0.5f * (2.0f * pv1.x + (pv2.x - pv0.x) * s + (2.0f * pv0.x - 5.0f * pv1.x + 4.0f * pv2.x - pv3.x) * s * s + + (pv3.x - 3.0f * pv2.x + 3.0f * pv1.x - pv0.x) * s * s * s); + pout.y = 0.5f * (2.0f * pv1.y + (pv2.y - pv0.y) * s + (2.0f * pv0.y - 5.0f * pv1.y + 4.0f * pv2.y - pv3.y) * s * s + + (pv3.y - 3.0f * pv2.y + 3.0f * pv1.y - pv0.y) * s * s * s); + pout.z = 0.5f * (2.0f * pv1.z + (pv2.z - pv0.z) * s + (2.0f * pv0.z - 5.0f * pv1.z + 4.0f * pv2.z - pv3.z) * s * s + + (pv3.z - 3.0f * pv2.z + 3.0f * pv1.z - pv0.z) * s * s * s); +} +//+------------------------------------------------------------------+ +//| Determines the cross-product of two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Cross(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = pv1.y * pv2.z - pv1.z * pv2.y; + pout.y = pv1.z * pv2.x - pv1.x * pv2.z; + pout.z = pv1.x * pv2.y - pv1.y * pv2.x; +} +//+------------------------------------------------------------------+ +//| Determines the dot product of two 3D vectors. | +//+------------------------------------------------------------------+ +float DXVec3Dot(const DXVector3 &pv1, const DXVector3 &pv2) { return (pv1.x * pv2.x + pv1.y * pv2.y + pv1.z * pv2.z); } +//+------------------------------------------------------------------+ +//| Performs a Hermite spline interpolation, | +//| using the specified 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Hermite(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pt1, const DXVector3 &pv2, + const DXVector3 &pt2, float s) { + float h1 = 2.0f * s * s * s - 3.0f * s * s + 1.0f; + float h2 = s * s * s - 2.0f * s * s + s; + float h3 = -2.0f * s * s * s + 3.0f * s * s; + float h4 = s * s * s - s * s; + //--- calculate interpolated coordinates + pout.x = h1 * pv1.x + h2 * pt1.x + h3 * pv2.x + h4 * pt2.x; + pout.y = h1 * pv1.y + h2 * pt1.y + h3 * pv2.y + h4 * pt2.y; + pout.z = h1 * pv1.z + h2 * pt1.z + h3 * pv2.z + h4 * pt2.z; +} +//+------------------------------------------------------------------+ +//| Returns the length of a 3D vector. | +//+------------------------------------------------------------------+ +float DXVec3Length(const DXVector3 &pv) { return ((float)sqrt(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z)); } +//+------------------------------------------------------------------+ +//| Returns the square of the length of a 3D vector. | +//+------------------------------------------------------------------+ +float DXVec3LengthSq(const DXVector3 &pv) { return ((float)(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z)); } +//+------------------------------------------------------------------+ +//| Performs a linear interpolation between two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Lerp(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2, float s) { + pout.x = (1.0f - s) * pv1.x + s * pv2.x; + pout.y = (1.0f - s) * pv1.y + s * pv2.y; + pout.z = (1.0f - s) * pv1.z + s * pv2.z; +} +//+------------------------------------------------------------------+ +//| Returns a 3D vector that is made up of the largest components | +//| of two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Maximize(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = (float)fmax(pv1.x, pv2.x); + pout.y = (float)fmax(pv1.y, pv2.y); + pout.z = (float)fmax(pv1.z, pv2.z); +} +//+------------------------------------------------------------------+ +//| Returns a 3D vector that is made up of the smallest components | +//| of two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Minimize(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = (float)fmin(pv1.x, pv2.x); + pout.y = (float)fmin(pv1.y, pv2.y); + pout.z = (float)fmin(pv1.z, pv2.z); +} +//+------------------------------------------------------------------+ +//| Returns the normalized version of a 3D vector. | +//+------------------------------------------------------------------+ +void DXVec3Normalize(DXVector3 &pout, const DXVector3 &pv) { + //--- calculate length + float norm = DXVec3Length(pv); + if (!norm) { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + } else { + pout.x = pv.x / norm; + pout.y = pv.y / norm; + pout.z = pv.z / norm; + } +} +//+------------------------------------------------------------------+ +//| Projects a 3D vector from object space into screen space. | +//+------------------------------------------------------------------+ +void DXVec3Project(DXVector3 &pout, const DXVector3 &pv, const DViewport &pviewport, const DXMatrix &pprojection, + const DXMatrix &pview, const DXMatrix &pworld) { + DXMatrix m; + DXMatrixIdentity(m); + //--- pworld + DXMatrixMultiply(m, m, pworld); + //--- pview + DXMatrixMultiply(m, m, pview); + //--- pprojection + DXMatrixMultiply(m, m, pprojection); + DXVec3TransformCoord(pout, pv, m); + //---pviewport + pout.x = pviewport.x + (1.0f + pout.x) * pviewport.width / 2.0f; + pout.y = pviewport.y + (1.0f - pout.y) * pviewport.height / 2.0f; + pout.z = pviewport.minz + pout.z * (pviewport.maxz - pviewport.minz); +} +//+------------------------------------------------------------------+ +//| Scales a 3D vector. | +//+------------------------------------------------------------------+ +void DXVec3Scale(DXVector3 &pout, const DXVector3 &pv, float s) { + pout.x = s * pv.x; + pout.y = s * pv.y; + pout.z = s * pv.z; +} +//+------------------------------------------------------------------+ +//| Subtracts two 3D vectors. | +//+------------------------------------------------------------------+ +void DXVec3Subtract(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) { + pout.x = pv1.x - pv2.x; + pout.y = pv1.y - pv2.y; + pout.z = pv1.z - pv2.z; +} +//+------------------------------------------------------------------+ +//| Transforms vector (x,y,z,1) by a given matrix. | +//+------------------------------------------------------------------+ +void DXVec3Transform(DXVector4 &pout, const DXVector3 &pv, const DXMatrix &pm) { + DXVector4 out; + //--- + out.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z + pm.m[3][0]; + out.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z + pm.m[3][1]; + out.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z + pm.m[3][2]; + out.w = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[2][3] * pv.z + pm.m[3][3]; + pout = out; +} +//+------------------------------------------------------------------+ +//| Transforms a 3D vector by a given matrix, | +//| projecting the result back into w = 1. | +//+------------------------------------------------------------------+ +void DXVec3TransformCoord(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { + float norm = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[2][3] * pv.z + pm.m[3][3]; + //--- + if (norm) { + pout.x = (pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z + pm.m[3][0]) / norm; + pout.y = (pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z + pm.m[3][1]) / norm; + pout.z = (pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z + pm.m[3][2]) / norm; + } else { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Transforms the 3D vector normal by the given matrix. | +//+------------------------------------------------------------------+ +void DXVec3TransformNormal(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { + pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z; + pout.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z; + pout.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z; +} +//+------------------------------------------------------------------+ +//| Projects a vector from screen space into object space. | +//+------------------------------------------------------------------+ +void DXVec3Unproject(DXVector3 &out, const DXVector3 &v, const DViewport &viewport, const DXMatrix &projection, + const DXMatrix &view, const DXMatrix &world) { + DXMatrix m; + DXMatrixIdentity(m); + //--- world + DXMatrixMultiply(m, m, world); + //--- view + DXMatrixMultiply(m, m, view); + //--- projection + DXMatrixMultiply(m, m, projection); + //--- calculate inverse matrix + float det = 0.0f; + DXMatrixInverse(m, det, m); + out = v; + //--- viewport + out.x = 2.0f * (out.x - viewport.x) / viewport.width - 1.0f; + out.y = 1.0f - 2.0f * (out.y - viewport.y) / viewport.height; + out.z = (out.z - viewport.minz) / (viewport.maxz - viewport.minz); + //--- + DXVec3TransformCoord(out, out, m); +} +//+------------------------------------------------------------------+ +//| Adds two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Add(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = pv1.x + pv2.x; + pout.y = pv1.y + pv2.y; + pout.z = pv1.z + pv2.z; + pout.w = pv1.w + pv2.w; +} +//+------------------------------------------------------------------+ +//| Returns a point in Barycentric coordinates, | +//| using the specified 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4BaryCentric(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2, const DXVector4 &pv3, float f, + float g) { + pout.x = (1.0f - f - g) * (pv1.x) + f * (pv2.x) + g * (pv3.x); + pout.y = (1.0f - f - g) * (pv1.y) + f * (pv2.y) + g * (pv3.y); + pout.z = (1.0f - f - g) * (pv1.z) + f * (pv2.z) + g * (pv3.z); + pout.w = (1.0f - f - g) * (pv1.w) + f * (pv2.w) + g * (pv3.w); +} +//+------------------------------------------------------------------+ +//| Performs a Catmull-Rom interpolation, | +//| using the specified 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4CatmullRom(DXVector4 &pout, const DXVector4 &pv0, const DXVector4 &pv1, const DXVector4 &pv2, + const DXVector4 &pv3, float s) { + pout.x = 0.5f * (2.0f * pv1.x + (pv2.x - pv0.x) * s + (2.0f * pv0.x - 5.0f * pv1.x + 4.0f * pv2.x - pv3.x) * s * s + + (pv3.x - 3.0f * pv2.x + 3.0f * pv1.x - pv0.x) * s * s * s); + pout.y = 0.5f * (2.0f * pv1.y + (pv2.y - pv0.y) * s + (2.0f * pv0.y - 5.0f * pv1.y + 4.0f * pv2.y - pv3.y) * s * s + + (pv3.y - 3.0f * pv2.y + 3.0f * pv1.y - pv0.y) * s * s * s); + pout.z = 0.5f * (2.0f * pv1.z + (pv2.z - pv0.z) * s + (2.0f * pv0.z - 5.0f * pv1.z + 4.0f * pv2.z - pv3.z) * s * s + + (pv3.z - 3.0f * pv2.z + 3.0f * pv1.z - pv0.z) * s * s * s); + pout.w = 0.5f * (2.0f * pv1.w + (pv2.w - pv0.w) * s + (2.0f * pv0.w - 5.0f * pv1.w + 4.0f * pv2.w - pv3.w) * s * s + + (pv3.w - 3.0f * pv2.w + 3.0f * pv1.w - pv0.w) * s * s * s); +} +//+------------------------------------------------------------------+ +//| Determines the cross-product in four dimensions. | +//+------------------------------------------------------------------+ +void DXVec4Cross(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2, const DXVector4 &pv3) { + DXVector4 out; + out.x = pv1.y * (pv2.z * pv3.w - pv3.z * pv2.w) - pv1.z * (pv2.y * pv3.w - pv3.y * pv2.w) + + pv1.w * (pv2.y * pv3.z - pv2.z * pv3.y); + out.y = -(pv1.x * (pv2.z * pv3.w - pv3.z * pv2.w) - pv1.z * (pv2.x * pv3.w - pv3.x * pv2.w) + + pv1.w * (pv2.x * pv3.z - pv3.x * pv2.z)); + out.z = pv1.x * (pv2.y * pv3.w - pv3.y * pv2.w) - pv1.y * (pv2.x * pv3.w - pv3.x * pv2.w) + + pv1.w * (pv2.x * pv3.y - pv3.x * pv2.y); + out.w = -(pv1.x * (pv2.y * pv3.z - pv3.y * pv2.z) - pv1.y * (pv2.x * pv3.z - pv3.x * pv2.z) + + pv1.z * (pv2.x * pv3.y - pv3.x * pv2.y)); + pout = out; +} +//+------------------------------------------------------------------+ +//| Determines the dot product of two 4D vectors. | +//+------------------------------------------------------------------+ +float DXVec4Dot(const DXVector4 &pv1, const DXVector4 &pv2) { + return (pv1.x * pv2.x + pv1.y * pv2.y + pv1.z * pv2.z + pv1.w * pv2.w); +} +//+------------------------------------------------------------------+ +//| Performs a Hermite spline interpolation, | +//| using the specified 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Hermite(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pt1, const DXVector4 &pv2, + const DXVector4 &pt2, float s) { + float h1 = 2.0f * s * s * s - 3.0f * s * s + 1.0f; + float h2 = s * s * s - 2.0f * s * s + s; + float h3 = -2.0f * s * s * s + 3.0f * s * s; + float h4 = s * s * s - s * s; + pout.x = h1 * pv1.x + h2 * pt1.x + h3 * pv2.x + h4 * pt2.x; + pout.y = h1 * pv1.y + h2 * pt1.y + h3 * pv2.y + h4 * pt2.y; + pout.z = h1 * pv1.z + h2 * pt1.z + h3 * pv2.z + h4 * pt2.z; + pout.w = h1 * pv1.w + h2 * pt1.w + h3 * pv2.w + h4 * pt2.w; +} +//+------------------------------------------------------------------+ +//| Returns the length of a 4D vector. | +//+------------------------------------------------------------------+ +float DXVec4Length(const DXVector4 &pv) { return ((float)sqrt(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z + pv.w * pv.w)); } +//+------------------------------------------------------------------+ +//| Returns the square of the length of a 4D vector. | +//+------------------------------------------------------------------+ +float DXVec4LengthSq(const DXVector4 &pv) { return ((float)(pv.x * pv.x + pv.y * pv.y + pv.z * pv.z)); } +//+------------------------------------------------------------------+ +//| Performs a linear interpolation between two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Lerp(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2, float s) { + pout.x = (1.0f - s) * pv1.x + s * pv2.x; + pout.y = (1.0f - s) * pv1.y + s * pv2.y; + pout.z = (1.0f - s) * pv1.z + s * pv2.z; + pout.w = (1.0f - s) * pv1.w + s * pv2.w; +} +//+------------------------------------------------------------------+ +//| Returns a 4D vector that is made up of the largest components | +//| of two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Maximize(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = (float)fmax(pv1.x, pv2.x); + pout.y = (float)fmax(pv1.y, pv2.y); + pout.z = (float)fmax(pv1.z, pv2.z); + pout.w = (float)fmax(pv1.w, pv2.w); +} +//+------------------------------------------------------------------+ +//| Returns a 4D vector that is made up of the smallest components | +//| of two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Minimize(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = (float)fmin(pv1.x, pv2.x); + pout.y = (float)fmin(pv1.y, pv2.y); + pout.z = (float)fmin(pv1.z, pv2.z); + pout.w = (float)fmin(pv1.w, pv2.w); +} +//+------------------------------------------------------------------+ +//| Returns the normalized version of a 4D vector. | +//+------------------------------------------------------------------+ +void DXVec4Normalize(DXVector4 &pout, const DXVector4 &pv) { + //--- calculate length + float norm = DXVec4Length(pv); + if (!norm) { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + pout.w = 0.0f; + } else { + pout.x = pv.x / norm; + pout.y = pv.y / norm; + pout.z = pv.z / norm; + pout.w = pv.w / norm; + } +} +//+------------------------------------------------------------------+ +//| Scales a 4D vector. | +//+------------------------------------------------------------------+ +void DXVec4Scale(DXVector4 &pout, const DXVector4 &pv, float s) { + pout.x = s * pv.x; + pout.y = s * pv.y; + pout.z = s * pv.z; + pout.w = s * pv.w; +} +//+------------------------------------------------------------------+ +//| Subtracts two 4D vectors. | +//+------------------------------------------------------------------+ +void DXVec4Subtract(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) { + pout.x = pv1.x - pv2.x; + pout.y = pv1.y - pv2.y; + pout.z = pv1.z - pv2.z; + pout.w = pv1.w - pv2.w; +} +//+------------------------------------------------------------------+ +//| Transforms a 4D vector by a given matrix. | +//+------------------------------------------------------------------+ +void DXVec4Transform(DXVector4 &pout, const DXVector4 &pv, const DXMatrix &pm) { + DXVector4 temp; + temp.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z + pm.m[3][0] * pv.w; + temp.y = pm.m[0][1] * pv.x + pm.m[1][1] * pv.y + pm.m[2][1] * pv.z + pm.m[3][1] * pv.w; + temp.z = pm.m[0][2] * pv.x + pm.m[1][2] * pv.y + pm.m[2][2] * pv.z + pm.m[3][2] * pv.w; + temp.w = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[2][3] * pv.z + pm.m[3][3] * pv.w; + pout = temp; +} +//+------------------------------------------------------------------+ +//| Returns a quaternion in barycentric coordinates. | +//+------------------------------------------------------------------+ +void DXQuaternionBaryCentric(DXQuaternion &pout, DXQuaternion &pq1, DXQuaternion &pq2, DXQuaternion &pq3, float f, + float g) { + DXQuaternion temp1, temp2; + DXQuaternionSlerp(temp1, pq1, pq2, f + g); + DXQuaternionSlerp(temp2, pq1, pq3, f + g); + DXQuaternionSlerp(pout, temp1, temp2, g / (f + g)); +} +//+------------------------------------------------------------------+ +//| Returns the conjugate of a quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionConjugate(DXQuaternion &pout, const DXQuaternion &pq) { + pout.x = -pq.x; + pout.y = -pq.y; + pout.z = -pq.z; + pout.w = pq.w; +} +//+------------------------------------------------------------------+ +//| Returns the dot product of two quaternions. | +//+------------------------------------------------------------------+ +float DXQuaternionDot(DXQuaternion &a, DXQuaternion &b) { return (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w); } +//+------------------------------------------------------------------+ +//| Calculates the exponential. | +//| This method converts a pure quaternion to a unit quaternion. | +//| DXQuaternionExp expects a pure quaternion, where w is ignored | +//| in the calculation (w == 0). | +//+------------------------------------------------------------------+ +void DXQuaternionExp(DXQuaternion &out, const DXQuaternion &q) { + float norm = (float)sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + if (norm) { + out.x = (float)sin(norm) * q.x / norm; + out.y = (float)sin(norm) * q.y / norm; + out.z = (float)sin(norm) * q.z / norm; + out.w = (float)cos(norm); + } else { + out.x = 0.0f; + out.y = 0.0f; + out.z = 0.0f; + out.w = 1.0f; + } +} +//+------------------------------------------------------------------+ +//| Returns the identity quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionIdentity(DXQuaternion &out) { + out.x = 0.0f; + out.y = 0.0f; + out.z = 0.0f; + out.w = 1.0f; +} +//+------------------------------------------------------------------+ +//| Determines if a quaternion is an identity quaternion. | +//+------------------------------------------------------------------+ +bool DXQuaternionIsIdentity(DXQuaternion &pq) { + return ((pq.x == 0.0f) && (pq.y == 0.0f) && (pq.z == 0.0f) && (pq.w == 1.0f)); +} +//+------------------------------------------------------------------+ +//| Returns the length of a quaternion. | +//+------------------------------------------------------------------+ +float DXQuaternionLength(const DXQuaternion &pq) { + return ((float)sqrt(pq.x * pq.x + pq.y * pq.y + pq.z * pq.z + pq.w * pq.w)); +} +//+------------------------------------------------------------------+ +//| Returns the square of the length of a quaternion. | +//+------------------------------------------------------------------+ +float DXQuaternionLengthSq(const DXQuaternion &pq) { + return ((float)(pq.x * pq.x + pq.y * pq.y + pq.z * pq.z + pq.w * pq.w)); +} +//+------------------------------------------------------------------+ +//| Conjugates and renormalizes a quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionInverse(DXQuaternion &pout, const DXQuaternion &pq) { + float norm = DXQuaternionLengthSq(pq); + pout.x = -pq.x / norm; + pout.y = -pq.y / norm; + pout.z = -pq.z / norm; + pout.w = pq.w / norm; +} +//+------------------------------------------------------------------+ +//| Calculates the natural logarithm. | +//| The DXQuaternionLn function works only for unit quaternions. | +//+------------------------------------------------------------------+ +void DXQuaternionLn(DXQuaternion &out, const DXQuaternion &q) { + float t; + if ((q.w >= 1.0f) || (q.w == -1.0f)) + t = 1.0f; + else + t = (float)(acos(q.w) / sqrt(1.0f - q.w * q.w)); + out.x = t * q.x; + out.y = t * q.y; + out.z = t * q.z; + out.w = 0.0f; +} +//+------------------------------------------------------------------+ +//| Multiplies two quaternions. | +//+------------------------------------------------------------------+ +void DXQuaternionMultiply(DXQuaternion &pout, const DXQuaternion &pq1, const DXQuaternion &pq2) { + DXQuaternion out; + out.x = pq2.w * pq1.x + pq2.x * pq1.w + pq2.y * pq1.z - pq2.z * pq1.y; + out.y = pq2.w * pq1.y - pq2.x * pq1.z + pq2.y * pq1.w + pq2.z * pq1.x; + out.z = pq2.w * pq1.z + pq2.x * pq1.y - pq2.y * pq1.x + pq2.z * pq1.w; + out.w = pq2.w * pq1.w - pq2.x * pq1.x - pq2.y * pq1.y - pq2.z * pq1.z; + pout = out; +} +//+------------------------------------------------------------------+ +//| Computes a unit length quaternion. | +//+------------------------------------------------------------------+ +void DXQuaternionNormalize(DXQuaternion &out, const DXQuaternion &q) { + float norm = DXQuaternionLength(q); + if (!norm) { + out.x = 0.0f; + out.y = 0.0f; + out.z = 0.0f; + out.w = 0.0f; + } else { + out.x = q.x / norm; + out.y = q.y / norm; + out.z = q.z / norm; + out.w = q.w / norm; + } +} +//+------------------------------------------------------------------+ +//| Rotates a quaternion about an arbitrary axis. | +//+------------------------------------------------------------------+ +void DXQuaternionRotationAxis(DXQuaternion &out, const DXVector3 &v, float angle) { + DXVector3 temp; + DXVec3Normalize(temp, v); + out.x = (float)sin(angle / 2.0f) * temp.x; + out.y = (float)sin(angle / 2.0f) * temp.y; + out.z = (float)sin(angle / 2.0f) * temp.z; + out.w = (float)cos(angle / 2.0f); +} +//+------------------------------------------------------------------+ +//| Builds a quaternion from a rotation matrix. | +//+------------------------------------------------------------------+ +void DXQuaternionRotationMatrix(DXQuaternion &out, const DXMatrix &m) { + float s; + float trace = m.m[0][0] + m.m[1][1] + m.m[2][2] + 1.0f; + if (trace > 1.0f) { + s = 2.0f * (float)sqrt(trace); + out.x = (m.m[1][2] - m.m[2][1]) / s; + out.y = (m.m[2][0] - m.m[0][2]) / s; + out.z = (m.m[0][1] - m.m[1][0]) / s; + out.w = 0.25f * s; + } else { + int maxi = 0; + for (int i = 1; i < 3; i++) { + if (m.m[i][i] > m.m[maxi][maxi]) maxi = i; + } + switch (maxi) { + case 0: + s = 2.0f * (float)sqrt(1.0f + m.m[0][0] - m.m[1][1] - m.m[2][2]); + out.x = 0.25f * s; + out.y = (m.m[0][1] + m.m[1][0]) / s; + out.z = (m.m[0][2] + m.m[2][0]) / s; + out.w = (m.m[1][2] - m.m[2][1]) / s; + break; + + case 1: + s = 2.0f * (float)sqrt(1.0f + m.m[1][1] - m.m[0][0] - m.m[2][2]); + out.x = (m.m[0][1] + m.m[1][0]) / s; + out.y = 0.25f * s; + out.z = (m.m[1][2] + m.m[2][1]) / s; + out.w = (m.m[2][0] - m.m[0][2]) / s; + break; + + case 2: + s = 2.0f * (float)sqrt(1.0f + m.m[2][2] - m.m[0][0] - m.m[1][1]); + out.x = (m.m[0][2] + m.m[2][0]) / s; + out.y = (m.m[1][2] + m.m[2][1]) / s; + out.z = 0.25f * s; + out.w = (m.m[0][1] - m.m[1][0]) / s; + break; + } + } +} +//+------------------------------------------------------------------+ +//| Builds a quaternion with the given yaw, pitch, and roll. | +//+------------------------------------------------------------------+ +void DXQuaternionRotationYawPitchRoll(DXQuaternion &out, float yaw, float pitch, float roll) { + float syaw = (float)sin(yaw / 2.0f); + float cyaw = (float)cos(yaw / 2.0f); + float spitch = (float)sin(pitch / 2.0f); + float cpitch = (float)cos(pitch / 2.0f); + float sroll = (float)sin(roll / 2.0f); + float croll = (float)cos(roll / 2.0f); + //--- + out.x = syaw * cpitch * sroll + cyaw * spitch * croll; + out.y = syaw * cpitch * croll - cyaw * spitch * sroll; + out.z = cyaw * cpitch * sroll - syaw * spitch * croll; + out.w = cyaw * cpitch * croll + syaw * spitch * sroll; +} +//+------------------------------------------------------------------+ +//| Interpolates between two quaternions, using spherical linear | +//| interpolation. | +//+------------------------------------------------------------------+ +void DXQuaternionSlerp(DXQuaternion &out, DXQuaternion &q1, DXQuaternion &q2, float t) { + float temp = 1.0f - t; + float dot = DXQuaternionDot(q1, q2); + if (dot < 0.0f) { + t = -t; + dot = -dot; + } + if (1.0f - dot > 0.001f) { + float theta = (float)acos(dot); + temp = (float)sin(theta * temp) / (float)sin(theta); + t = (float)sin(theta * t) / (float)sin(theta); + } + out.x = temp * q1.x + t * q2.x; + out.y = temp * q1.y + t * q2.y; + out.z = temp * q1.z + t * q2.z; + out.w = temp * q1.w + t * q2.w; +} +//+------------------------------------------------------------------+ +//| Interpolates between quaternions, using spherical quadrangle | +//| interpolation. | +//+------------------------------------------------------------------+ +void DXQuaternionSquad(DXQuaternion &pout, DXQuaternion &pq1, DXQuaternion &pq2, DXQuaternion &pq3, DXQuaternion &pq4, + float t) { + DXQuaternion temp1, temp2; + DXQuaternionSlerp(temp1, pq1, pq4, t); + DXQuaternionSlerp(temp2, pq2, pq3, t); + DXQuaternionSlerp(pout, temp1, temp2, 2.0f * t * (1.0f - t)); +} +//+------------------------------------------------------------------+ +//| add_diff | +//+------------------------------------------------------------------+ +DXQuaternion add_diff(const DXQuaternion &q1, const DXQuaternion &q2, const float add) { + DXQuaternion temp; + temp.x = q1.x + add * q2.x; + temp.y = q1.y + add * q2.y; + temp.z = q1.z + add * q2.z; + temp.w = q1.w + add * q2.w; + //--- + return (temp); +} +//+------------------------------------------------------------------+ +//| Sets up control points for spherical quadrangle interpolation. | +//+------------------------------------------------------------------+ +void DXQuaternionSquadSetup(DXQuaternion &paout, DXQuaternion &pbout, DXQuaternion &pcout, DXQuaternion &pq0, + DXQuaternion &pq1, DXQuaternion &pq2, DXQuaternion &pq3) { + DXQuaternion q, temp1, temp2, temp3, zero; + DXQuaternion aout, cout; + zero.x = 0.0f; + zero.y = 0.0f; + zero.z = 0.0f; + zero.w = 0.0f; + //--- + if (DXQuaternionDot(pq0, pq1) < 0.0f) + temp2 = add_diff(zero, pq0, -1.0f); + else + temp2 = pq0; + //--- + if (DXQuaternionDot(pq1, pq2) < 0.0f) + cout = add_diff(zero, pq2, -1.0f); + else + cout = pq2; + //--- + if (DXQuaternionDot(cout, pq3) < 0.0f) + temp3 = add_diff(zero, pq3, -1.0f); + else + temp3 = pq3; + //--- + DXQuaternionInverse(temp1, pq1); + DXQuaternionMultiply(temp2, temp1, temp2); + DXQuaternionLn(temp2, temp2); + DXQuaternionMultiply(q, temp1, cout); + DXQuaternionLn(q, q); + temp1 = add_diff(temp2, q, 1.0f); + temp1.x *= -0.25f; + temp1.y *= -0.25f; + temp1.z *= -0.25f; + temp1.w *= -0.25f; + DXQuaternionExp(temp1, temp1); + DXQuaternionMultiply(aout, pq1, temp1); + //--- + DXQuaternionInverse(temp1, cout); + DXQuaternionMultiply(temp2, temp1, pq1); + DXQuaternionLn(temp2, temp2); + DXQuaternionMultiply(q, temp1, temp3); + DXQuaternionLn(q, q); + temp1 = add_diff(temp2, q, 1.0f); + temp1.x *= -0.25f; + temp1.y *= -0.25f; + temp1.z *= -0.25f; + temp1.w *= -0.25f; + DXQuaternionExp(temp1, temp1); + DXQuaternionMultiply(pbout, cout, temp1); + paout = aout; + pcout = cout; +} +//+------------------------------------------------------------------+ +//| Computes a quaternion's axis and angle of rotation. | +//+------------------------------------------------------------------+ +void DXQuaternionToAxisAngle(const DXQuaternion &pq, DXVector3 &paxis, float &pangle) { + //--- paxis + paxis.x = pq.x; + paxis.y = pq.y; + paxis.z = pq.z; + //--- pangle + pangle = 2.0f * (float)acos(pq.w); +} +//+------------------------------------------------------------------+ +//| DXMatrixIdentity creates an identity matrix | +//+------------------------------------------------------------------+ +void DXMatrixIdentity(DXMatrix &out) { + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) { + if (i == j) + out.m[j, i] = 1.0f; + else + out.m[j, i] = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Determines if a matrix is an identity matrix. | +//+------------------------------------------------------------------+ +bool DXMatrixIsIdentity(DXMatrix &pm) { + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) { + if (i == j) { + if (fabs(pm.m[j, i] - 1.0f) > 1e-6f) return (false); + } else if (fabs(pm.m[j, i]) > 1e-6f) + return (false); + } + //--- + return (true); +} +//+------------------------------------------------------------------+ +//| Builds a 3D affine transformation matrix. | +//+------------------------------------------------------------------+ +//| This function calculates the affine transformation matrix | +//| with the following formula, with matrix concatenation | +//| evaluated in left-to-right order: | +//| Mout = Ms * (Mrc)-1 * Mr * Mrc * Mt | +//| where: | +//| Mout = output matrix (pOut) | +//| Ms = scaling matrix (Scaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (pRotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixAffineTransformation(DXMatrix &out, float scaling, const DXVector3 &rotationcenter, + const DXQuaternion &rotation, const DXVector3 &translation) { + DXMatrixIdentity(out); + //--- rotation + float temp00 = 1.0f - 2.0f * (rotation.y * rotation.y + rotation.z * rotation.z); + float temp01 = 2.0f * (rotation.x * rotation.y + rotation.z * rotation.w); + float temp02 = 2.0f * (rotation.x * rotation.z - rotation.y * rotation.w); + float temp10 = 2.0f * (rotation.x * rotation.y - rotation.z * rotation.w); + float temp11 = 1.0f - 2.0f * (rotation.x * rotation.x + rotation.z * rotation.z); + float temp12 = 2.0f * (rotation.y * rotation.z + rotation.x * rotation.w); + float temp20 = 2.0f * (rotation.x * rotation.z + rotation.y * rotation.w); + float temp21 = 2.0f * (rotation.y * rotation.z - rotation.x * rotation.w); + float temp22 = 1.0f - 2.0f * (rotation.x * rotation.x + rotation.y * rotation.y); + //--- scaling + out.m[0][0] = scaling * temp00; + out.m[0][1] = scaling * temp01; + out.m[0][2] = scaling * temp02; + out.m[1][0] = scaling * temp10; + out.m[1][1] = scaling * temp11; + out.m[1][2] = scaling * temp12; + out.m[2][0] = scaling * temp20; + out.m[2][1] = scaling * temp21; + out.m[2][2] = scaling * temp22; + //--- rotationcenter + out.m[3][0] = rotationcenter.x * (1.0f - temp00) - rotationcenter.y * temp10 - rotationcenter.z * temp20; + out.m[3][1] = rotationcenter.y * (1.0f - temp11) - rotationcenter.x * temp01 - rotationcenter.z * temp21; + out.m[3][2] = rotationcenter.z * (1.0f - temp22) - rotationcenter.x * temp02 - rotationcenter.y * temp12; + //--- translation + out.m[3][0] += translation.x; + out.m[3][1] += translation.y; + out.m[3][2] += translation.z; +} +//+------------------------------------------------------------------+ +//| Builds a 2D affine transformation matrix in the xy plane. | +//+------------------------------------------------------------------+ +//| This function calculates the affine transformation matrix | +//| with the following formula, with matrix concatenation evaluated | +//| in left-to-right order: | +//| Mout = Ms * (Mrc)^(-1) * Mr * Mrc * Mt | +//| where: | +//| Mout = output matrix (pOut) | +//| Ms = scaling matrix (Scaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (Rotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector2 &rotationcenter, float rotation, + const DXVector2 &translation) { + float s = (float)sin(rotation / 2.0f); + float tmp1 = 1.0f - 2.0f * s * s; + float tmp2 = 2.0f * s * (float)cos(rotation / 2.0f); + //--- + DXMatrixIdentity(out); + out.m[0][0] = scaling * tmp1; + out.m[0][1] = scaling * tmp2; + out.m[1][0] = -scaling * tmp2; + out.m[1][1] = scaling * tmp1; + //--- rotationcenter + float x = rotationcenter.x; + float y = rotationcenter.y; + out.m[3][0] = y * tmp2 - x * tmp1 + x; + out.m[3][1] = -x * tmp2 - y * tmp1 + y; + //--- translation + out.m[3][0] += translation.x; + out.m[3][1] += translation.y; +} +#define D3DERR_INVALIDCALL -2005530516 +//#define S_OK 0; +//+------------------------------------------------------------------+ +//| Breaks down a general 3D transformation matrix into its scalar, | +//| rotational, and translational components. | +//+------------------------------------------------------------------+ +int DXMatrixDecompose(DXVector3 &poutscale, DXQuaternion &poutrotation, DXVector3 &pouttranslation, + const DXMatrix &pm) { + DXMatrix normalized; + DXVector3 vec; + //--- Compute the scaling part + vec.x = pm.m[0][0]; + vec.y = pm.m[0][1]; + vec.z = pm.m[0][2]; + poutscale.x = DXVec3Length(vec); + vec.x = pm.m[1][0]; + vec.y = pm.m[1][1]; + vec.z = pm.m[1][2]; + poutscale.y = DXVec3Length(vec); + vec.x = pm.m[2][0]; + vec.y = pm.m[2][1]; + vec.z = pm.m[2][2]; + poutscale.z = DXVec3Length(vec); + //--- compute the translation part + pouttranslation.x = pm.m[3][0]; + pouttranslation.y = pm.m[3][1]; + pouttranslation.z = pm.m[3][2]; + //--- let's calculate the rotation now + if ((poutscale.x == 0.0f) || (poutscale.y == 0.0f) || (poutscale.z == 0.0f)) return (D3DERR_INVALIDCALL); + //--- + normalized.m[0][0] = pm.m[0][0] / poutscale.x; + normalized.m[0][1] = pm.m[0][1] / poutscale.x; + normalized.m[0][2] = pm.m[0][2] / poutscale.x; + normalized.m[1][0] = pm.m[1][0] / poutscale.y; + normalized.m[1][1] = pm.m[1][1] / poutscale.y; + normalized.m[1][2] = pm.m[1][2] / poutscale.y; + normalized.m[2][0] = pm.m[2][0] / poutscale.z; + normalized.m[2][1] = pm.m[2][1] / poutscale.z; + normalized.m[2][2] = pm.m[2][2] / poutscale.z; + DXQuaternionRotationMatrix(poutrotation, normalized); + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Returns the determinant of a matrix. | +//+------------------------------------------------------------------+ +float DXMatrixDeterminant(const DXMatrix &pm) { + float t[3], v[4]; + t[0] = pm.m[2][2] * pm.m[3][3] - pm.m[2][3] * pm.m[3][2]; + t[1] = pm.m[1][2] * pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; + t[2] = pm.m[1][2] * pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; + v[0] = pm.m[1][1] * t[0] - pm.m[2][1] * t[1] + pm.m[3][1] * t[2]; + v[1] = -pm.m[1][0] * t[0] + pm.m[2][0] * t[1] - pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[1][0] * pm.m[2][1] - pm.m[2][0] * pm.m[1][1]; + t[1] = pm.m[1][0] * pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; + t[2] = pm.m[2][0] * pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; + v[2] = pm.m[3][3] * t[0] - pm.m[2][3] * t[1] + pm.m[1][3] * t[2]; + v[3] = -pm.m[3][2] * t[0] + pm.m[2][2] * t[1] - pm.m[1][2] * t[2]; + //--- + return (pm.m[0][0] * v[0] + pm.m[0][1] * v[1] + pm.m[0][2] * v[2] + pm.m[0][3] * v[3]); +} +//+------------------------------------------------------------------+ +//| Calculates the inverse of a matrix. | +//+------------------------------------------------------------------+ +void DXMatrixInverse(DXMatrix &pout, float &pdeterminant, const DXMatrix &pm) { + float t[3], v[16]; + t[0] = pm.m[2][2] * pm.m[3][3] - pm.m[2][3] * pm.m[3][2]; + t[1] = pm.m[1][2] * pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; + t[2] = pm.m[1][2] * pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; + v[0] = pm.m[1][1] * t[0] - pm.m[2][1] * t[1] + pm.m[3][1] * t[2]; + v[4] = -pm.m[1][0] * t[0] + pm.m[2][0] * t[1] - pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[1][0] * pm.m[2][1] - pm.m[2][0] * pm.m[1][1]; + t[1] = pm.m[1][0] * pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; + t[2] = pm.m[2][0] * pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; + v[8] = pm.m[3][3] * t[0] - pm.m[2][3] * t[1] + pm.m[1][3] * t[2]; + v[12] = -pm.m[3][2] * t[0] + pm.m[2][2] * t[1] - pm.m[1][2] * t[2]; + //--- + float det = pm.m[0][0] * v[0] + pm.m[0][1] * v[4] + pm.m[0][2] * v[8] + pm.m[0][3] * v[12]; + if (det == 0.0f) { + for (int j = 0; j < 4; j++) + for (int i = 0; i < 4; i++) { + pout.m[j, i] = 0.0; + } + //--- + return; + } + if (pdeterminant) pdeterminant = det; + //--- + t[0] = pm.m[2][2] * pm.m[3][3] - pm.m[2][3] * pm.m[3][2]; + t[1] = pm.m[0][2] * pm.m[3][3] - pm.m[0][3] * pm.m[3][2]; + t[2] = pm.m[0][2] * pm.m[2][3] - pm.m[0][3] * pm.m[2][2]; + v[1] = -pm.m[0][1] * t[0] + pm.m[2][1] * t[1] - pm.m[3][1] * t[2]; + v[5] = pm.m[0][0] * t[0] - pm.m[2][0] * t[1] + pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[0][0] * pm.m[2][1] - pm.m[2][0] * pm.m[0][1]; + t[1] = pm.m[3][0] * pm.m[0][1] - pm.m[0][0] * pm.m[3][1]; + t[2] = pm.m[2][0] * pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; + v[9] = -pm.m[3][3] * t[0] - pm.m[2][3] * t[1] - pm.m[0][3] * t[2]; + v[13] = pm.m[3][2] * t[0] + pm.m[2][2] * t[1] + pm.m[0][2] * t[2]; + //--- + t[0] = pm.m[1][2] * pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; + t[1] = pm.m[0][2] * pm.m[3][3] - pm.m[0][3] * pm.m[3][2]; + t[2] = pm.m[0][2] * pm.m[1][3] - pm.m[0][3] * pm.m[1][2]; + v[2] = pm.m[0][1] * t[0] - pm.m[1][1] * t[1] + pm.m[3][1] * t[2]; + v[6] = -pm.m[0][0] * t[0] + pm.m[1][0] * t[1] - pm.m[3][0] * t[2]; + //--- + t[0] = pm.m[0][0] * pm.m[1][1] - pm.m[1][0] * pm.m[0][1]; + t[1] = pm.m[3][0] * pm.m[0][1] - pm.m[0][0] * pm.m[3][1]; + t[2] = pm.m[1][0] * pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; + v[10] = pm.m[3][3] * t[0] + pm.m[1][3] * t[1] + pm.m[0][3] * t[2]; + v[14] = -pm.m[3][2] * t[0] - pm.m[1][2] * t[1] - pm.m[0][2] * t[2]; + //--- + t[0] = pm.m[1][2] * pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; + t[1] = pm.m[0][2] * pm.m[2][3] - pm.m[0][3] * pm.m[2][2]; + t[2] = pm.m[0][2] * pm.m[1][3] - pm.m[0][3] * pm.m[1][2]; + v[3] = -pm.m[0][1] * t[0] + pm.m[1][1] * t[1] - pm.m[2][1] * t[2]; + v[7] = pm.m[0][0] * t[0] - pm.m[1][0] * t[1] + pm.m[2][0] * t[2]; + //--- + v[11] = -pm.m[0][0] * (pm.m[1][1] * pm.m[2][3] - pm.m[1][3] * pm.m[2][1]) + + pm.m[1][0] * (pm.m[0][1] * pm.m[2][3] - pm.m[0][3] * pm.m[2][1]) - + pm.m[2][0] * (pm.m[0][1] * pm.m[1][3] - pm.m[0][3] * pm.m[1][1]); + //--- + v[15] = pm.m[0][0] * (pm.m[1][1] * pm.m[2][2] - pm.m[1][2] * pm.m[2][1]) - + pm.m[1][0] * (pm.m[0][1] * pm.m[2][2] - pm.m[0][2] * pm.m[2][1]) + + pm.m[2][0] * (pm.m[0][1] * pm.m[1][2] - pm.m[0][2] * pm.m[1][1]); + //--- + det = 1.0f / det; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) pout.m[i][j] = v[4 * i + j] * det; +} +//+------------------------------------------------------------------+ +//| Builds a left-handed,look-at matrix. | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| | +//| zaxis = normal(At - Eye) | +//| xaxis = normal(cross(Up,zaxis)) | +//| yaxis = cross(zaxis,xaxis) | +//| | +//| xaxis.x yaxis.x zaxis.x 0 | +//| xaxis.y yaxis.y zaxis.y 0 | +//| xaxis.z yaxis.z zaxis.z 0 | +//| -dot(xaxis,eye) -dot(yaxis,eye) -dot(zaxis,eye) 1 | +//+------------------------------------------------------------------+ +void DXMatrixLookAtLH(DXMatrix &out, const DXVector3 &eye, const DXVector3 &at, const DXVector3 &up) { + DXVector3 right, upn, vec; + DXVec3Subtract(vec, at, eye); + DXVec3Normalize(vec, vec); + DXVec3Cross(right, up, vec); + DXVec3Cross(upn, vec, right); + DXVec3Normalize(right, right); + DXVec3Normalize(upn, upn); + //--- + out.m[0][0] = right.x; + out.m[1][0] = right.y; + out.m[2][0] = right.z; + out.m[3][0] = -DXVec3Dot(right, eye); + out.m[0][1] = upn.x; + out.m[1][1] = upn.y; + out.m[2][1] = upn.z; + out.m[3][1] = -DXVec3Dot(upn, eye); + out.m[0][2] = vec.x; + out.m[1][2] = vec.y; + out.m[2][2] = vec.z; + out.m[3][2] = -DXVec3Dot(vec, eye); + out.m[0][3] = 0.0f; + out.m[1][3] = 0.0f; + out.m[2][3] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Builds a right-handed, look-at matrix. | +//+------------------------------------------------------------------+ +//| This function uses the following formula to compute | +//| the returned matrix. | +//| | +//| zaxis = normal(Eye - At) | +//| xaxis = normal(cross(Up,zaxis)) | +//| yaxis = cross(zaxis,xaxis) | +//| | +//| xaxis.x yaxis.x zaxis.x 0 | +//| xaxis.y yaxis.y zaxis.y 0 | +//| xaxis.z yaxis.z zaxis.z 0 | +//| dot(xaxis,eye) dot(yaxis,eye) dot(zaxis,eye) 1 | +//+------------------------------------------------------------------+ +void DXMatrixLookAtRH(DXMatrix &out, const DXVector3 &eye, const DXVector3 &at, const DXVector3 &up) { + DXVector3 right, upn, vec; + DXVec3Subtract(vec, at, eye); + DXVec3Normalize(vec, vec); + DXVec3Cross(right, up, vec); + DXVec3Cross(upn, vec, right); + DXVec3Normalize(right, right); + DXVec3Normalize(upn, upn); + //--- + out.m[0][0] = -right.x; + out.m[1][0] = -right.y; + out.m[2][0] = -right.z; + out.m[3][0] = DXVec3Dot(right, eye); + out.m[0][1] = upn.x; + out.m[1][1] = upn.y; + out.m[2][1] = upn.z; + out.m[3][1] = -DXVec3Dot(upn, eye); + out.m[0][2] = -vec.x; + out.m[1][2] = -vec.y; + out.m[2][2] = -vec.z; + out.m[3][2] = DXVec3Dot(vec, eye); + out.m[0][3] = 0.0f; + out.m[1][3] = 0.0f; + out.m[2][3] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Determines the product of two matrices. | +//+------------------------------------------------------------------+ +void DXMatrixMultiply(DXMatrix &pout, const DXMatrix &pm1, const DXMatrix &pm2) { + DXMatrix out = {}; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + out.m[i][j] = + pm1.m[i][0] * pm2.m[0][j] + pm1.m[i][1] * pm2.m[1][j] + pm1.m[i][2] * pm2.m[2][j] + pm1.m[i][3] * pm2.m[3][j]; + } + } + pout = out; +} +//+------------------------------------------------------------------+ +//| Calculates the transposed product of two matrices. | +//+------------------------------------------------------------------+ +void DXMatrixMultiplyTranspose(DXMatrix &pout, const DXMatrix &pm1, const DXMatrix &pm2) { + DXMatrix temp = {}; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + temp.m[j][i] = + pm1.m[i][0] * pm2.m[0][j] + pm1.m[i][1] * pm2.m[1][j] + pm1.m[i][2] * pm2.m[2][j] + pm1.m[i][3] * pm2.m[3][j]; + pout = temp; +} +//+------------------------------------------------------------------+ +//| Builds a left-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +void DXMatrixOrthoLH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f / w; + pout.m[1][1] = 2.0f / h; + pout.m[2][2] = 1.0f / (zf - zn); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a customized,left-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +void DXMatrixOrthoOffCenterLH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f / (r - l); + pout.m[1][1] = 2.0f / (t - b); + pout.m[2][2] = 1.0f / (zf - zn); + pout.m[3][0] = -1.0f - 2.0f * l / (r - l); + pout.m[3][1] = 1.0f + 2.0f * t / (b - t); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a customized,right-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +void DXMatrixOrthoOffCenterRH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f / (r - l); + pout.m[1][1] = 2.0f / (t - b); + pout.m[2][2] = 1.0f / (zn - zf); + pout.m[3][0] = -1.0f - 2.0f * l / (r - l); + pout.m[3][1] = 1.0f + 2.0f * t / (b - t); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a right-handed orthographic projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixOrthoRH function | +//| are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix: | +//| 2/w 0 0 0 | +//| 0 2/h 0 0 | +//| 0 0 1/(zn-zf) 0 | +//| 0 0 zn/(zn-zf) 1 | +//+------------------------------------------------------------------+ +void DXMatrixOrthoRH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + pout.m[0][0] = 2.0f / w; + pout.m[1][1] = 2.0f / h; + pout.m[2][2] = 1.0f / (zn - zf); + pout.m[3][2] = zn / (zn - zf); +} +//+------------------------------------------------------------------+ +//| Builds a left-handed perspective projection matrix | +//| based on a field of view. | +//+------------------------------------------------------------------+ +//| This function computes the returned matrix as shown: | +//| xScale 0 0 0 | +//| 0 yScale 0 0 | +//| 0 0 zf/(zf-zn) 1 | +//| 0 0 -zn*zf/(zf-zn) 0 | +//| where: | +//| yScale = cot(fovY/2) | +//| xScale = yScale / aspect ratio | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveFovLH(DXMatrix &pout, float fovy, float aspect, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f / (aspect * (float)tan(fovy / 2.0f)); + pout.m[1][1] = 1.0f / (float)tan(fovy / 2.0f); + pout.m[2][2] = zf / (zf - zn); + pout.m[2][3] = 1.0f; + pout.m[3][2] = (zf * zn) / (zn - zf); + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a right-handed perspective projection matrix | +//| based on a field of view. | +//+------------------------------------------------------------------+ +//| This function computes the returned matrix as shown. | +//| xScale 0 0 0 | +//| 0 yScale 0 0 | +//| 0 0 zf/(zn-zf) -1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//| where: | +//| yScale = cot(fovY/2) | +//| xScale = yScale / aspect ratio | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveFovRH(DXMatrix &pout, float fovy, float aspect, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f / (aspect * (float)tan(fovy / 2.0f)); + pout.m[1][1] = 1.0f / (float)tan(fovy / 2.0f); + pout.m[2][2] = zf / (zn - zf); + pout.m[2][3] = -1.0f; + pout.m[3][2] = (zf * zn) / (zn - zf); + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a left-handed perspective projection matrix | +//+------------------------------------------------------------------+ +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/w 0 0 0 | +//| 0 2*zn/h 0 0 | +//| 0 0 zf/(zf-zn) 1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveLH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + pout.m[0][0] = 2.0f * zn / w; + pout.m[1][1] = 2.0f * zn / h; + pout.m[2][2] = zf / (zf - zn); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = 1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a customized, left-handed perspective projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixPerspectiveOffCenterLH | +//| function are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/(r-l) 0 0 0 | +//| 0 2*zn/(t-b) 0 0 | +//| (l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f * zn / (r - l); + pout.m[1][1] = -2.0f * zn / (b - t); + pout.m[2][0] = -1.0f - 2.0f * l / (r - l); + pout.m[2][1] = 1.0f + 2.0f * t / (b - t); + pout.m[2][2] = -zf / (zn - zf); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = 1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a customized, right-handed perspective projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixPerspectiveOffCenterRH | +//| function are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/(r-l) 0 0 0 | +//| 0 2*zn/(t-b) 0 0 | +//| (l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f * zn / (r - l); + pout.m[1][1] = -2.0f * zn / (b - t); + pout.m[2][0] = 1.0f + 2.0f * l / (r - l); + pout.m[2][1] = -1.0f - 2.0f * t / (b - t); + pout.m[2][2] = zf / (zn - zf); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = -1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a right-handed perspective projection matrix. | +//+------------------------------------------------------------------+ +//| All the parameters of the DXMatrixPerspectiveRH function | +//| are distances in camera space. The parameters describe | +//| the dimensions of the view volume. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| 2*zn/w 0 0 0 | +//| 0 2*zn/h 0 0 | +//| 0 0 zf/(zn-zf) -1 | +//| 0 0 zn*zf/(zn-zf) 0 | +//+------------------------------------------------------------------+ +void DXMatrixPerspectiveRH(DXMatrix &pout, float w, float h, float zn, float zf) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 2.0f * zn / w; + pout.m[1][1] = 2.0f * zn / h; + pout.m[2][2] = zf / (zn - zf); + pout.m[3][2] = (zn * zf) / (zn - zf); + pout.m[2][3] = -1.0f; + pout.m[3][3] = 0.0f; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that reflects the coordinate system about a plane| +//| This function normalizes the plane equation before it creates | +//| the reflected matrix. | +//| | +//| This function uses the following formula to compute | +//| the returned matrix. | +//| P = normalize(Plane); | +//| -2 * P.a * P.a + 1 -2 * P.b * P.a -2 * P.c * P.a 0 | +//| -2 * P.a * P.b -2 * P.b * P.b + 1 -2 * P.c * P.b 0 | +//| -2 * P.a * P.c -2 * P.b * P.c -2 * P.c * P.c + 1 0 | +//| -2 * P.a * P.d -2 * P.b * P.d -2 * P.c * P.d 1 | +//+------------------------------------------------------------------+ +void DXMatrixReflect(DXMatrix &pout, const DXPlane &pplane) { + DXPlane Nplane; + DXPlaneNormalize(Nplane, pplane); + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f - 2.0f * Nplane.a * Nplane.a; + pout.m[0][1] = -2.0f * Nplane.a * Nplane.b; + pout.m[0][2] = -2.0f * Nplane.a * Nplane.c; + pout.m[1][0] = -2.0f * Nplane.a * Nplane.b; + pout.m[1][1] = 1.0f - 2.0f * Nplane.b * Nplane.b; + pout.m[1][2] = -2.0f * Nplane.b * Nplane.c; + pout.m[2][0] = -2.0f * Nplane.c * Nplane.a; + pout.m[2][1] = -2.0f * Nplane.c * Nplane.b; + pout.m[2][2] = 1.0f - 2.0f * Nplane.c * Nplane.c; + pout.m[3][0] = -2.0f * Nplane.d * Nplane.a; + pout.m[3][1] = -2.0f * Nplane.d * Nplane.b; + pout.m[3][2] = -2.0f * Nplane.d * Nplane.c; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around an arbitrary axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationAxis(DXMatrix &out, const DXVector3 &v, float angle) { + DXVector3 nv; + DXVec3Normalize(nv, v); + //--- + float sangle = (float)sin(angle); + float cangle = (float)cos(angle); + float cdiff = 1.0f - cangle; + //--- + out.m[0][0] = cdiff * nv.x * nv.x + cangle; + out.m[1][0] = cdiff * nv.x * nv.y - sangle * nv.z; + out.m[2][0] = cdiff * nv.x * nv.z + sangle * nv.y; + out.m[3][0] = 0.0f; + out.m[0][1] = cdiff * nv.y * nv.x + sangle * nv.z; + out.m[1][1] = cdiff * nv.y * nv.y + cangle; + out.m[2][1] = cdiff * nv.y * nv.z - sangle * nv.x; + out.m[3][1] = 0.0f; + out.m[0][2] = cdiff * nv.z * nv.x - sangle * nv.y; + out.m[1][2] = cdiff * nv.z * nv.y + sangle * nv.x; + out.m[2][2] = cdiff * nv.z * nv.z + cangle; + out.m[3][2] = 0.0f; + out.m[0][3] = 0.0f; + out.m[1][3] = 0.0f; + out.m[2][3] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Builds a rotation matrix from a quaternion. | +//+------------------------------------------------------------------+ +void DXMatrixRotationQuaternion(DXMatrix &pout, const DXQuaternion &pq) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = 1.0f - 2.0f * (pq.y * pq.y + pq.z * pq.z); + pout.m[0][1] = 2.0f * (pq.x * pq.y + pq.z * pq.w); + pout.m[0][2] = 2.0f * (pq.x * pq.z - pq.y * pq.w); + pout.m[1][0] = 2.0f * (pq.x * pq.y - pq.z * pq.w); + pout.m[1][1] = 1.0f - 2.0f * (pq.x * pq.x + pq.z * pq.z); + pout.m[1][2] = 2.0f * (pq.y * pq.z + pq.x * pq.w); + pout.m[2][0] = 2.0f * (pq.x * pq.z + pq.y * pq.w); + pout.m[2][1] = 2.0f * (pq.y * pq.z - pq.x * pq.w); + pout.m[2][2] = 1.0f - 2.0f * (pq.x * pq.x + pq.y * pq.y); +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around the x-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationX(DXMatrix &pout, float angle) { + DXMatrixIdentity(pout); + //--- + pout.m[1][1] = (float)cos(angle); + pout.m[2][2] = (float)cos(angle); + pout.m[1][2] = (float)sin(angle); + pout.m[2][1] = -(float)sin(angle); +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around the y-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationY(DXMatrix &pout, float angle) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = (float)cos(angle); + pout.m[2][2] = (float)cos(angle); + pout.m[0][2] = -(float)sin(angle); + pout.m[2][0] = (float)sin(angle); +} +//+------------------------------------------------------------------+ +//| Builds a matrix with a specified yaw, pitch, and roll. | +//+------------------------------------------------------------------+ +//| The order of transformations is roll first, then pitch, then yaw.| +//| Relative to the object's local coordinate axis, this is | +//| equivalent to rotation around the z-axis, followed by rotation | +//| around the x-axis, followed by rotation around the y-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationYawPitchRoll(DXMatrix &out, float yaw, float pitch, float roll) { + float sroll = (float)sin(roll); + float croll = (float)cos(roll); + float spitch = (float)sin(pitch); + float cpitch = (float)cos(pitch); + float syaw = (float)sin(yaw); + float cyaw = (float)cos(yaw); + //--- + out.m[0][0] = sroll * spitch * syaw + croll * cyaw; + out.m[0][1] = sroll * cpitch; + out.m[0][2] = sroll * spitch * cyaw - croll * syaw; + out.m[0][3] = 0.0f; + out.m[1][0] = croll * spitch * syaw - sroll * cyaw; + out.m[1][1] = croll * cpitch; + out.m[1][2] = croll * spitch * cyaw + sroll * syaw; + out.m[1][3] = 0.0f; + out.m[2][0] = cpitch * syaw; + out.m[2][1] = -spitch; + out.m[2][2] = cpitch * cyaw; + out.m[2][3] = 0.0f; + out.m[3][0] = 0.0f; + out.m[3][1] = 0.0f; + out.m[3][2] = 0.0f; + out.m[3][3] = 1.0f; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that rotates around the z-axis. | +//+------------------------------------------------------------------+ +void DXMatrixRotationZ(DXMatrix &pout, float angle) { + DXMatrixIdentity(pout); + //--- + pout.m[0][0] = (float)cos(angle); + pout.m[1][1] = (float)cos(angle); + pout.m[0][1] = (float)sin(angle); + pout.m[1][0] = -(float)sin(angle); +} +//+------------------------------------------------------------------+ +//| Builds a matrix that scales along the x-axis, | +//| the y-axis,and the z-axis. | +//+------------------------------------------------------------------+ +void DXMatrixScaling(DXMatrix &pout, float sx, float sy, float sz) { + DXMatrixIdentity(pout); + pout.m[0][0] = sx; + pout.m[1][1] = sy; + pout.m[2][2] = sz; +} +//+------------------------------------------------------------------+ +//| Builds a matrix that flattens geometry into a plane. | +//+------------------------------------------------------------------+ +//| The DXMatrixShadow function flattens geometry into a plane, as | +//| if casting a shadow from a light. | +//| This function uses the following formula to compute the returned | +//| matrix. | +//| | +//| P = normalize(Plane); | +//| L = Light; | +//| d = -dot(P,L) | +//| | +//| P.a * L.x + d P.a * L.y P.a * L.z P.a * L.w | +//| P.b * L.x P.b * L.y + d P.b * L.z P.b * L.w | +//| P.c * L.x P.c * L.y P.c * L.z + d P.c * L.w | +//| P.d * L.x P.d * L.y P.d * L.z P.d * L.w + d | +//| | +//| If the light's w-component is 0, the ray from the origin to the | +//| light represents a directional light. If it is 1,the light is | +//| a point light. | +//+------------------------------------------------------------------+ +void DXMatrixShadow(DXMatrix &pout, const DXVector4 &plight, const DXPlane &pplane) { + DXPlane Nplane; + DXPlaneNormalize(Nplane, pplane); + float dot = DXPlaneDot(Nplane, plight); + //--- + pout.m[0][0] = dot - Nplane.a * plight.x; + pout.m[0][1] = -Nplane.a * plight.y; + pout.m[0][2] = -Nplane.a * plight.z; + pout.m[0][3] = -Nplane.a * plight.w; + pout.m[1][0] = -Nplane.b * plight.x; + pout.m[1][1] = dot - Nplane.b * plight.y; + pout.m[1][2] = -Nplane.b * plight.z; + pout.m[1][3] = -Nplane.b * plight.w; + pout.m[2][0] = -Nplane.c * plight.x; + pout.m[2][1] = -Nplane.c * plight.y; + pout.m[2][2] = dot - Nplane.c * plight.z; + pout.m[2][3] = -Nplane.c * plight.w; + pout.m[3][0] = -Nplane.d * plight.x; + pout.m[3][1] = -Nplane.d * plight.y; + pout.m[3][2] = -Nplane.d * plight.z; + pout.m[3][3] = dot - Nplane.d * plight.w; +} +//+------------------------------------------------------------------+ +//| Builds a transformation matrix. | +//+------------------------------------------------------------------+ +//| This function calculates the transformation matrix with the | +//| following formula, with matrix concatenation evaluated | +//| in left-to-right order: | +//| | +//| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | +//| | +//| where: | +//| Mout = output matrix (pOut) | +//| Msc = scaling center matrix (pScalingCenter) | +//| Msr = scaling rotation matrix (pScalingRotation) | +//| Ms = scaling matrix (pScaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (pRotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixTransformation(DXMatrix &pout, const DXVector3 &pscalingcenter, const DXQuaternion &pscalingrotation, + const DXVector3 &pscaling, const DXVector3 &protationcenter, const DXQuaternion &protation, + const DXVector3 &ptranslation) { + DXMatrix m1, m2, m3, m4, m5, m6, m7; + DXQuaternion prc; + DXVector3 psc, pt; + //--- pscalingcenter + psc.x = pscalingcenter.x; + psc.y = pscalingcenter.y; + psc.z = pscalingcenter.z; + //--- protationcenter + prc.x = protationcenter.x; + prc.y = protationcenter.y; + prc.z = protationcenter.z; + //--- ptranslation + pt.x = ptranslation.x; + pt.y = ptranslation.y; + pt.z = ptranslation.z; + DXMatrixTranslation(m1, -psc.x, -psc.y, -psc.z); + //--- + DXQuaternion temp; + DXMatrixRotationQuaternion(m4, pscalingrotation); + temp.w = pscalingrotation.w; + temp.x = -pscalingrotation.x; + temp.y = -pscalingrotation.y; + temp.z = -pscalingrotation.z; + DXMatrixRotationQuaternion(m2, temp); + //--- pscaling + DXMatrixScaling(m3, pscaling.x, pscaling.y, pscaling.z); + //--- protation + DXMatrixRotationQuaternion(m6, protation); + //--- + DXMatrixTranslation(m5, psc.x - prc.x, psc.y - prc.y, psc.z - prc.z); + DXMatrixTranslation(m7, prc.x + pt.x, prc.y + pt.y, prc.z + pt.z); + DXMatrixMultiply(m1, m1, m2); + DXMatrixMultiply(m1, m1, m3); + DXMatrixMultiply(m1, m1, m4); + DXMatrixMultiply(m1, m1, m5); + DXMatrixMultiply(m1, m1, m6); + DXMatrixMultiply(pout, m1, m7); +} +//+------------------------------------------------------------------+ +//| Builds a 2D transformation matrix that represents | +//| transformations in the xy plane. | +//+------------------------------------------------------------------+ +//| This function calculates the transformation matrix with the | +//| following formula, with matrix concatenation evaluated | +//| in left-to-right order: | +//| | +//| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | +//| | +//| where: | +//| Mout = output matrix (pOut) | +//| Msc = scaling center matrix (pScalingCenter) | +//| Msr = scaling rotation matrix (pScalingRotation) | +//| Ms = scaling matrix (pScaling) | +//| Mrc = center of rotation matrix (pRotationCenter) | +//| Mr = rotation matrix (Rotation) | +//| Mt = translation matrix (pTranslation) | +//+------------------------------------------------------------------+ +void DXMatrixTransformation2D(DXMatrix &pout, const DXVector2 &pscalingcenter, float scalingrotation, + const DXVector2 &pscaling, const DXVector2 &protationcenter, float rotation, + const DXVector2 &ptranslation) { + DXQuaternion rot, sca_rot; + DXVector3 rot_center, sca, sca_center, trans; + //--- pscalingcenter + sca_center.x = pscalingcenter.x; + sca_center.y = pscalingcenter.y; + sca_center.z = 0.0f; + //--- pscaling + sca.x = pscaling.x; + sca.y = pscaling.y; + sca.z = 1.0f; + //--- protationcenter + rot_center.x = protationcenter.x; + rot_center.y = protationcenter.y; + rot_center.z = 0.0f; + //--- ptranslation + trans.x = ptranslation.x; + trans.y = ptranslation.y; + trans.z = 0.0f; + //--- + rot.w = (float)cos(rotation / 2.0f); + rot.x = 0.0f; + rot.y = 0.0f; + rot.z = (float)sin(rotation / 2.0f); + //--- + sca_rot.w = (float)cos(scalingrotation / 2.0f); + sca_rot.x = 0.0f; + sca_rot.y = 0.0f; + sca_rot.z = (float)sin(scalingrotation / 2.0f); + DXMatrixTransformation(pout, sca_center, sca_rot, sca, rot_center, rot, trans); +} +//+------------------------------------------------------------------+ +//| Builds a matrix using the specified offsets. | +//+------------------------------------------------------------------+ +void DXMatrixTranslation(DXMatrix &pout, float x, float y, float z) { + DXMatrixIdentity(pout); + //--- + pout.m[3][0] = x; + pout.m[3][1] = y; + pout.m[3][2] = z; +} +//+------------------------------------------------------------------+ +//| Returns the matrix transpose of a matrix. | +//+------------------------------------------------------------------+ +void DXMatrixTranspose(DXMatrix &pout, const DXMatrix &pm) { + const DXMatrix m = pm; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) pout.m[i][j] = m.m[j][i]; +} +//+------------------------------------------------------------------+ +//| Computes the dot product of a plane and a 4D vector. | +//+------------------------------------------------------------------+ +float DXPlaneDot(const DXPlane &p1, const DXVector4 &p2) { + return (p1.a * p2.x + p1.b * p2.y + p1.c * p2.z + p1.d * p2.w); +} +//+------------------------------------------------------------------+ +//| Computes the dot product of a plane and a 3D vector. | +//| The w parameter of the vector is assumed to be 1. | +//+------------------------------------------------------------------+ +float DXPlaneDotCoord(const DXPlane &pp, const DXVector4 &pv) { + return (pp.a * pv.x + pp.b * pv.y + pp.c * pv.z + pp.d); +} +//+------------------------------------------------------------------+ +//| Computes the dot product of a plane and a 3D vector. | +//| The w parameter of the vector is assumed to be 0. | +//+------------------------------------------------------------------+ +float DXPlaneDotNormal(const DXPlane &pp, const DXVector4 &pv) { return (pp.a * pv.x + pp.b * pv.y + pp.c * pv.z); } +//+------------------------------------------------------------------+ +//| Constructs a plane from a point and a normal. | +//+------------------------------------------------------------------+ +void DXPlaneFromPointNormal(DXPlane &pout, const DXVector3 &pvpoint, const DXVector3 &pvnormal) { + pout.a = pvnormal.x; + pout.b = pvnormal.y; + pout.c = pvnormal.z; + pout.d = -DXVec3Dot(pvpoint, pvnormal); +} +//+------------------------------------------------------------------+ +//| Constructs a plane from three points. | +//+------------------------------------------------------------------+ +void DXPlaneFromPoints(DXPlane &pout, const DXVector3 &pv1, const DXVector3 &pv2, const DXVector3 &pv3) { + DXVector3 edge1, edge2, normal, Nnormal; + //--- + edge1.x = 0.0f; + edge1.y = 0.0f; + edge1.z = 0.0f; + edge2.x = 0.0f; + edge2.y = 0.0f; + edge2.z = 0.0f; + //--- + DXVec3Subtract(edge1, pv2, pv1); + DXVec3Subtract(edge2, pv3, pv1); + DXVec3Cross(normal, edge1, edge2); + DXVec3Normalize(Nnormal, normal); + DXPlaneFromPointNormal(pout, pv1, Nnormal); +} +//+------------------------------------------------------------------+ +//| Finds the intersection between a plane and a line. | +//| If the line is parallel to the plane, null vector is returned. | +//+------------------------------------------------------------------+ +void DXPlaneIntersectLine(DXVector3 &pout, const DXPlane &pp, const DXVector3 &pv1, const DXVector3 &pv2) { + DXVector3 direction, normal; + normal.x = pp.a; + normal.y = pp.b; + normal.z = pp.c; + direction.x = pv2.x - pv1.x; + direction.y = pv2.y - pv1.y; + direction.z = pv2.z - pv1.z; + //--- + float dot = DXVec3Dot(normal, direction); + if (!dot) { + pout.x = 0.0f; + pout.y = 0.0f; + pout.z = 0.0f; + } + float temp = (pp.d + DXVec3Dot(normal, pv1)) / dot; + pout.x = pv1.x - temp * direction.x; + pout.y = pv1.y - temp * direction.y; + pout.z = pv1.z - temp * direction.z; +} +//+------------------------------------------------------------------+ +//| Normalizes the plane coefficients so that the plane normal | +//| has unit length. | +//| This function normalizes a plane so that |a,b,c| == 1. | +//+------------------------------------------------------------------+ +void DXPlaneNormalize(DXPlane &out, const DXPlane &p) { + float norm = (float)sqrt(p.a * p.a + p.b * p.b + p.c * p.c); + if (norm) { + out.a = p.a / norm; + out.b = p.b / norm; + out.c = p.c / norm; + out.d = p.d / norm; + } else { + out.a = 0.0f; + out.b = 0.0f; + out.c = 0.0f; + out.d = 0.0f; + } +} +//+------------------------------------------------------------------+ +//| Scale the plane with the given scaling factor. | +//+------------------------------------------------------------------+ +void DXPlaneScale(DXPlane &pout, const DXPlane &p, float s) { + pout.a = p.a * s; + pout.b = p.b * s; + pout.c = p.c * s; + pout.d = p.d * s; +}; +//+------------------------------------------------------------------+ +//| Transforms a plane by a matrix. | +//| The input matrix is the inverse transpose of the actual | +//| transformation. | +//+------------------------------------------------------------------+ +void DXPlaneTransform(DXPlane &pout, const DXPlane &pplane, const DXMatrix &pm) { + DXPlane plane = pplane; + //--- + pout.a = pm.m[0][0] * plane.a + pm.m[1][0] * plane.b + pm.m[2][0] * plane.c + pm.m[3][0] * plane.d; + pout.b = pm.m[0][1] * plane.a + pm.m[1][1] * plane.b + pm.m[2][1] * plane.c + pm.m[3][1] * plane.d; + pout.c = pm.m[0][2] * plane.a + pm.m[1][2] * plane.b + pm.m[2][2] * plane.c + pm.m[3][2] * plane.d; + pout.d = pm.m[0][3] * plane.a + pm.m[1][3] * plane.b + pm.m[2][3] * plane.c + pm.m[3][3] * plane.d; +} +//+------------------------------------------------------------------+ +//| Adds two spherical harmonic (SH) vectors; in other words, | +//| out[i] = a[i] + b[i]. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) is stored | +//| at memory location l^2 + m + l,where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHAdd(float &out[], int order, const float &a[], const float &b[]) { + for (int i = 0; i < order * order; i++) out[i] = a[i] + b[i]; +} +//+------------------------------------------------------------------+ +//| Computes the dot product of two spherical harmonic (SH) vectors. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) is stored | +//| at memory location l^2 + m + l,where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l,inclusive. | +//+------------------------------------------------------------------+ +float DXSHDot(int order, const float &a[], const float &b[]) { + float s = a[0] * b[0]; + for (int i = 1; i < order * order; i++) s += a[i] * b[i]; + //--- + return (s); +} +//+------------------------------------------------------------------+ +//| weightedcapintegrale | +//+------------------------------------------------------------------+ +void weightedcapintegrale(float &out[], uint order, float angle) { + float coeff[3]; + coeff[0] = (float)cos(angle); + + out[0] = 2.0f * DX_PI * (1.0f - coeff[0]); + out[1] = DX_PI * (float)sin(angle) * (float)sin(angle); + if (order <= 2) return; + + out[2] = coeff[0] * out[1]; + if (order == 3) return; + + coeff[1] = coeff[0] * coeff[0]; + coeff[2] = coeff[1] * coeff[1]; + + out[3] = DX_PI * (-1.25f * coeff[2] + 1.5f * coeff[1] - 0.25f); + if (order == 4) return; + + out[4] = -0.25f * DX_PI * coeff[0] * (7.0f * coeff[2] - 10.0f * coeff[1] + 3.0f); + if (order == 5) return; + + out[5] = DX_PI * (-2.625f * coeff[2] * coeff[1] + 4.375f * coeff[2] - 1.875f * coeff[1] + 0.125f); +} +//+------------------------------------------------------------------+ +//| Evaluates a light that is a cone of constant intensity | +//| and returns spectral spherical harmonic (SH) data. | +//+------------------------------------------------------------------+ +//| Evaluates a light that is a cone of constant intensity and | +//| returns spectral SH data. | +//| The output vector is computed so that if the intensity ratio | +//| R/G/B is equal to 1, the exit radiance of a point | +//| directly under the light (oriented in the cone direction | +//| on a diffuse object with an albedo of 1) would be 1.0. | +//| This will compute three spectral samples; | +//| rout[], gout[] and bout[] will be computed. | +//+------------------------------------------------------------------+ +int DXSHEvalConeLight(int order, const DXVector3 &dir, float radius, float Rintensity, float Gintensity, + float Bintensity, float &rout[], float &gout[], float &bout[]) { + float cap[6]; + //--- + if (radius <= 0.0f) + return (DXSHEvalDirectionalLight(order, dir, Rintensity, Gintensity, Bintensity, rout, gout, bout)); + //--- + float clamped_angle = (radius > DX_PI / 2.0f) ? (DX_PI / 2.0f) : radius; + float norm = (float)sin(clamped_angle) * (float)sin(clamped_angle); + if (order > DXSH_MAXORDER) { + //--- order clamped at DXSH_MAXORDER + order = DXSH_MAXORDER; + } + //--- + weightedcapintegrale(cap, order, radius); + DXSHEvalDirection(rout, order, dir); + //--- + for (int i = 0; i < order; i++) { + float scale = cap[i] / norm; + for (int j = 0; j < 2 * i + 1; j++) { + int index = i * i + j; + float temp = rout[index] * scale; + rout[index] = temp * Rintensity; + gout[index] = temp * Gintensity; + bout[index] = temp * Bintensity; + } + } + return (0); +} +//+------------------------------------------------------------------+ +//| Evaluates the spherical harmonic (SH) basis functions | +//| from an input direction vector. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) is stored | +//| at memory location l^2 + m + l, where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHEvalDirection(float &out[], int order, const DXVector3 &dir) { + const float dirxx = dir.x * dir.x; + const float dirxy = dir.x * dir.y; + const float dirxz = dir.x * dir.z; + const float diryy = dir.y * dir.y; + const float diryz = dir.y * dir.z; + const float dirzz = dir.z * dir.z; + const float dirxxxx = dirxx * dirxx; + const float diryyyy = diryy * diryy; + const float dirzzzz = dirzz * dirzz; + const float dirxyxy = dirxy * dirxy; + //--- + if ((order < DXSH_MINORDER) || (order > DXSH_MAXORDER)) return; + + out[0] = 0.5f / (float)sqrt(DX_PI); + out[1] = -0.5f / (float)sqrt(DX_PI / 3.0f) * dir.y; + out[2] = 0.5f / (float)sqrt(DX_PI / 3.0f) * dir.z; + out[3] = -0.5f / (float)sqrt(DX_PI / 3.0f) * dir.x; + if (order == 2) return; + + out[4] = 0.5f / (float)sqrt(DX_PI / 15.0f) * dirxy; + out[5] = -0.5f / (float)sqrt(DX_PI / 15.0f) * diryz; + out[6] = 0.25f / (float)sqrt(DX_PI / 5.0f) * (3.0f * dirzz - 1.0f); + out[7] = -0.5f / (float)sqrt(DX_PI / 15.0f) * dirxz; + out[8] = 0.25f / (float)sqrt(DX_PI / 15.0f) * (dirxx - diryy); + if (order == 3) return; + + out[9] = -(float)sqrt(70.0f / DX_PI) / 8.0f * dir.y * (3.0f * dirxx - diryy); + out[10] = (float)sqrt(105.0f / DX_PI) / 2.0f * dirxy * dir.z; + out[11] = -(float)sqrt(42.0f / DX_PI) / 8.0f * dir.y * (-1.0f + 5.0f * dirzz); + out[12] = (float)sqrt(7.0f / DX_PI) / 4.0f * dir.z * (5.0f * dirzz - 3.0f); + out[13] = (float)sqrt(42.0f / DX_PI) / 8.0f * dir.x * (1.0f - 5.0f * dirzz); + out[14] = (float)sqrt(105.0f / DX_PI) / 4.0f * dir.z * (dirxx - diryy); + out[15] = -(float)sqrt(70.0f / DX_PI) / 8.0f * dir.x * (dirxx - 3.0f * diryy); + if (order == 4) return; + + out[16] = 0.75f * float(sqrt(35.0f / DX_PI)) * dirxy * (dirxx - diryy); + out[17] = 3.0f * dir.z * out[9]; + out[18] = 0.75f * (float)sqrt(5.0f / DX_PI) * dirxy * (7.0f * dirzz - 1.0f); + out[19] = 0.375f * (float)sqrt(10.0f / DX_PI) * diryz * (3.0f - 7.0f * dirzz); + out[20] = 3.0f / (16.0f * (float)sqrt(DX_PI)) * (35.0f * dirzzzz - 30.f * dirzz + 3.0f); + out[21] = 0.375f * (float)sqrt(10.0f / DX_PI) * dirxz * (3.0f - 7.0f * dirzz); + out[22] = 0.375f * (float)sqrt(5.0f / DX_PI) * (dirxx - diryy) * (7.0f * dirzz - 1.0f); + out[23] = 3.0f * dir.z * out[15]; + out[24] = 3.0f / 16.0f * float(sqrt(35.0f / DX_PI)) * (dirxxxx - 6.0f * dirxyxy + diryyyy); + if (order == 5) return; + + out[25] = -3.0f / 32.0f * (float)sqrt(154.0f / DX_PI) * dir.y * (5.0f * dirxxxx - 10.0f * dirxyxy + diryyyy); + out[26] = 0.75f * (float)sqrt(385.0f / DX_PI) * dirxy * dir.z * (dirxx - diryy); + out[27] = (float)sqrt(770.0f / DX_PI) / 32.0f * dir.y * (3.0f * dirxx - diryy) * (1.0f - 9.0f * dirzz); + out[28] = (float)sqrt(1155.0f / DX_PI) / 4.0f * dirxy * dir.z * (3.0f * dirzz - 1.0f); + out[29] = (float)sqrt(165.0f / DX_PI) / 16.0f * dir.y * (14.0f * dirzz - 21.0f * dirzzzz - 1.0f); + out[30] = (float)sqrt(11.0f / DX_PI) / 16.0f * dir.z * (63.0f * dirzzzz - 70.0f * dirzz + 15.0f); + out[31] = (float)sqrt(165.0f / DX_PI) / 16.0f * dir.x * (14.0f * dirzz - 21.0f * dirzzzz - 1.0f); + out[32] = (float)sqrt(1155.0f / DX_PI) / 8.0f * dir.z * (dirxx - diryy) * (3.0f * dirzz - 1.0f); + out[33] = (float)sqrt(770.0f / DX_PI) / 32.0f * dir.x * (dirxx - 3.0f * diryy) * (1.0f - 9.0f * dirzz); + out[34] = 3.0f / 16.0f * (float)sqrt(385.0f / DX_PI) * dir.z * (dirxxxx - 6.0f * dirxyxy + diryyyy); + out[35] = -3.0f / 32.0f * (float)sqrt(154.0f / DX_PI) * dir.x * (dirxxxx - 10.0f * dirxyxy + 5.0f * diryyyy); +} +//+------------------------------------------------------------------+ +//| Evaluates a directional light and | +//| returns spectral spherical harmonic (SH) data. | +//+------------------------------------------------------------------+ +//| The output vector is computed so that if the intensity ratio | +//| R/G/B is equal to 1 ,the resulting exit radiance of a point | +//| directly under the light on a diffuse object with an albedo | +//| of 1 would be 1.0. This will compute three spectral samples; | +//| rout[], gout[] and bout[] will be returned. | +//+------------------------------------------------------------------+ +int DXSHEvalDirectionalLight(int order, const DXVector3 &dir, float Rintensity, float Gintensity, float Bintensity, + float &rout[], float &gout[], float &bout[]) { + float s = 0.75f; + if (order > 2) s += 5.0f / 16.0f; + if (order > 4) s -= 3.0f / 32.0f; + s /= DX_PI; + + DXSHEvalDirection(rout, order, dir); + for (int j = 0; j < order * order; j++) { + float temp = rout[j] / s; + rout[j] = Rintensity * temp; + gout[j] = Gintensity * temp; + bout[j] = Bintensity * temp; + } + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Evaluates a light that is a linear interpolation | +//| between two colors over the sphere. | +//+------------------------------------------------------------------+ +//| The interpolation is done linearly between the two points, | +//| not over the surface of the sphere (that is, if the axis was | +//| (0,0,1) it is linear in Z, not in the azimuthal angle). | +//| The resulting spherical lighting function is normalized so that | +//| a point on a perfectly diffuse surface with no shadowing | +//| and a normal pointed in the direction pDir would result in exit | +//| radiance with a value of 1 (if the top color was white | +//| and the bottom color was black). This is a very simple model | +//| where Top represents the intensity of the "sky" | +//| and Bottom represents the intensity of the "ground". | +//+------------------------------------------------------------------+ +int DXSHEvalHemisphereLight(int order, const DXVector3 &dir, DXColor &top, DXColor &bottom, float &rout[], + float &gout[], float &bout[]) { + float a[2], temp[4]; + DXSHEvalDirection(temp, 2, dir); + //--- rout + a[0] = (top.r + bottom.r) * 3.0f * DX_PI; + a[1] = (top.r - bottom.r) * DX_PI; + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) + if (i < 2) + rout[i * i + j] = temp[i * i + j] * a[i]; + else + rout[i * i + j] = 0.0f; + //--- gout + a[0] = (top.g + bottom.g) * 3.0f * DX_PI; + a[1] = (top.g - bottom.g) * DX_PI; + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) + if (i < 2) + gout[i * i + j] = temp[i * i + j] * a[i]; + else + gout[i * i + j] = 0.0f; + //--- bout + a[0] = (top.b + bottom.b) * 3.0f * DX_PI; + a[1] = (top.b - bottom.b) * DX_PI; + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) + if (i < 2) + bout[i * i + j] = temp[i * i + j] * a[i]; + else + bout[i * i + j] = 0.0f; + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Evaluates a spherical light and returns | +//| spectral spherical harmonic (SH) data. | +//+------------------------------------------------------------------+ +//| There is no normalization of the intensity of the light like | +//| there is for directional lights, so care has to be taken when | +//| specifying the intensities. | +//| This will compute three spectral samples; | +//| rout[], gout[], bout[] will be returned. | +//+------------------------------------------------------------------+ +int DXSHEvalSphericalLight(int order, const DXVector3 &dir, float radius, float Rintensity, float Gintensity, + float Bintensity, float &rout[], float &gout[], float &bout[]) { + DXVector3 normal; + float cap[6]; + //--- check order + if (order > DXSH_MAXORDER) order = DXSH_MAXORDER; + //--- check radius + if (radius < 0.0f) radius = -radius; + + float dist = DXVec3Length(dir); + float clamped_angle = (dist <= radius) ? DX_PI / 2.0f : (float)asin(radius / dist); + + weightedcapintegrale(cap, order, clamped_angle); + DXVec3Normalize(normal, dir); + DXSHEvalDirection(rout, order, normal); + + for (int i = 0; i < order; i++) + for (int j = 0; j < 2 * i + 1; j++) { + int index = i * i + j; + float temp = rout[index] * cap[i]; + rout[index] = temp * Rintensity; + gout[index] = temp * Gintensity; + bout[index] = temp * Bintensity; + } + //--- + return (0); +} +//+------------------------------------------------------------------+ +//| Computes the product of two functions represented | +//| using Spherical Harmonics (f and g). | +//+------------------------------------------------------------------+ +//| The order is a number between 2 and 6 inclusive. | +//| So it's the same for the several functions: | +//| DXSHMultiply2, DXSHMultiply3, ... DXSHMultiply6. | +//| | +//| Computes the product of two functions represented | +//| using SH (f and g),where | +//| out[i] = int(y_i(s) * f(s) * g(s)), | +//| where | +//| y_i(s) is the ith SH basis function, | +//| f(s) and g(s) are SH functions (sum_i(y_i(s)*c_i)). | +//| The order determines the lengths of the arrays, where there | +//| should always be l^2 coefficients. | +//| | +//| In general the product of two SH functions of order l generates | +//| an SH function of order 2*l - 1, but the results are truncated. | +//| | +//| This means that the product commutes (f*g == g*f) | +//| but doesn't associate (f*(g*h) != (f*g)*h. | +//+------------------------------------------------------------------+ +void DXSHMultiply2(float &out[], const float &a[], const float &b[]) { + float ta = 0.28209479f * a[0]; + float tb = 0.28209479f * b[0]; + out[0] = 0.28209479f * DXSHDot(2, a, b); + out[1] = ta * b[1] + tb * a[1]; + out[2] = ta * b[2] + tb * a[2]; + out[3] = ta * b[3] + tb * a[3]; +} +//+------------------------------------------------------------------+ +//| Computes the product of two functions represented using | +//| Spherical Harmonics (f and g). Both functions are of order N=3. | +//+------------------------------------------------------------------+ +//| The order is a number between 2 and 6 inclusive. | +//| So it's the same for the several functions: | +//| DXSHMultiply2, DXSHMultiply3, ... DXSHMultiply6. | +//| | +//| Computes the product of two functions represented | +//| using SH (f and g),where | +//| out[i] = int(y_i(s) * f(s) * g(s)), | +//| where | +//| y_i(s) is the ith SH basis function, | +//| f(s) and g(s) are SH functions (sum_i(y_i(s)*c_i)). | +//| The order determines the lengths of the arrays,where there | +//| should always be l^2 coefficients. | +//| | +//| In general the product of two SH functions of order l generates | +//| an SH function of order 2*l - 1, but the results are truncated. | +//| | +//| This means that the product commutes (f*g == g*f) | +//| but doesn't associate (f*(g*h) != (f*g)*h. | +//+------------------------------------------------------------------+ +void DXSHMultiply3(float &out[], const float &a[], const float &b[]) { + out[0] = 0.28209479f * a[0] * b[0]; + float ta = 0.28209479f * a[0] - 0.12615663f * a[6] - 0.21850969f * a[8]; + float tb = 0.28209479f * b[0] - 0.12615663f * b[6] - 0.21850969f * b[8]; + out[1] = ta * b[1] + tb * a[1]; + float t = a[1] * b[1]; + out[0] += 0.28209479f * t; + out[6] = -0.12615663f * t; + out[8] = -0.21850969f * t; + + ta = 0.21850969f * a[5]; + tb = 0.21850969f * b[5]; + out[1] += ta * b[2] + tb * a[2]; + out[2] = ta * b[1] + tb * a[1]; + t = a[1] * b[2] + a[2] * b[1]; + out[5] = 0.21850969f * t; + + ta = 0.21850969f * a[4]; + tb = 0.21850969f * b[4]; + out[1] += ta * b[3] + tb * a[3]; + out[3] = ta * b[1] + tb * a[1]; + t = a[1] * b[3] + a[3] * b[1]; + out[4] = 0.21850969f * t; + + ta = 0.28209480f * a[0] + 0.25231326f * a[6]; + tb = 0.28209480f * b[0] + 0.25231326f * b[6]; + out[2] += ta * b[2] + tb * a[2]; + t = a[2] * b[2]; + out[0] += 0.28209480f * t; + out[6] += 0.25231326f * t; + + ta = 0.21850969f * a[7]; + tb = 0.21850969f * b[7]; + out[2] += ta * b[3] + tb * a[3]; + out[3] += ta * b[2] + tb * a[2]; + t = a[2] * b[3] + a[3] * b[2]; + out[7] = 0.21850969f * t; + + ta = 0.28209479f * a[0] - 0.12615663f * a[6] + 0.21850969f * a[8]; + tb = 0.28209479f * b[0] - 0.12615663f * b[6] + 0.21850969f * b[8]; + out[3] += ta * b[3] + tb * a[3]; + t = a[3] * b[3]; + out[0] += 0.28209479f * t; + out[6] -= 0.12615663f * t; + out[8] += 0.21850969f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[4] += ta * b[4] + tb * a[4]; + t = a[4] * b[4]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; + + ta = 0.15607835f * a[7]; + tb = 0.15607835f * b[7]; + out[4] += ta * b[5] + tb * a[5]; + out[5] += ta * b[4] + tb * a[4]; + t = a[4] * b[5] + a[5] * b[4]; + out[7] += 0.15607835f * t; + + ta = 0.28209479f * a[0] + 0.09011188f * a[6] - 0.15607835f * a[8]; + tb = 0.28209479f * b[0] + 0.09011188f * b[6] - 0.15607835f * b[8]; + out[5] += ta * b[5] + tb * a[5]; + t = a[5] * b[5]; + out[0] += 0.28209479f * t; + out[6] += 0.09011188f * t; + out[8] -= 0.15607835f * t; + + ta = 0.28209480f * a[0]; + tb = 0.28209480f * b[0]; + out[6] += ta * b[6] + tb * a[6]; + t = a[6] * b[6]; + out[0] += 0.28209480f * t; + out[6] += 0.18022376f * t; + + ta = 0.28209479f * a[0] + 0.09011188f * a[6] + 0.15607835f * a[8]; + tb = 0.28209479f * b[0] + 0.09011188f * b[6] + 0.15607835f * b[8]; + out[7] += ta * b[7] + tb * a[7]; + t = a[7] * b[7]; + out[0] += 0.28209479f * t; + out[6] += 0.09011188f * t; + out[8] += 0.15607835f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[8] += ta * b[8] + tb * a[8]; + t = a[8] * b[8]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; +} +//+------------------------------------------------------------------+ +//| Computes the product of two functions represented using | +//| Spherical Harmonics (f and g). Both functions are of order N=4. | +//+------------------------------------------------------------------+ +//| The order is a number between 2 and 6 inclusive. | +//| So it's the same for the several functions: | +//| DXSHMultiply2, DXSHMultiply3, ... DXSHMultiply6. | +//| | +//| Computes the product of two functions represented | +//| using SH (f and g), where | +//| out[i] = int(y_i(s) * f(s) * g(s)), | +//| where | +//| y_i(s) is the ith SH basis function, | +//| f(s) and g(s) are SH functions (sum_i(y_i(s)*c_i)). | +//| The order determines the lengths of the arrays,where there | +//| should always be l^2 coefficients. | +//| | +//| In general the product of two SH functions of order l generates | +//| an SH function of order 2*l - 1, but the results are truncated. | +//| | +//| This means that the product commutes (f*g == g*f) | +//| but doesn't associate (f*(g*h) != (f*g)*h. | +//+------------------------------------------------------------------+ +void DXSHMultiply4(float &out[], const float &a[], const float &b[]) { + out[0] = 0.28209479f * a[0] * b[0]; + float ta = 0.28209479f * a[0] - 0.12615663f * a[6] - 0.21850969f * a[8]; + float tb = 0.28209479f * b[0] - 0.12615663f * b[6] - 0.21850969f * b[8]; + out[1] = ta * b[1] + tb * a[1]; + float t = a[1] * b[1]; + out[0] += 0.28209479f * t; + out[6] = -0.12615663f * t; + out[8] = -0.21850969f * t; + + ta = 0.21850969f * a[3] - 0.05839917f * a[13] - 0.22617901f * a[15]; + tb = 0.21850969f * b[3] - 0.05839917f * b[13] - 0.22617901f * b[15]; + out[1] += ta * b[4] + tb * a[4]; + out[4] = ta * b[1] + tb * a[1]; + t = a[1] * b[4] + a[4] * b[1]; + out[3] = 0.21850969f * t; + out[13] = -0.05839917f * t; + out[15] = -0.22617901f * t; + + ta = 0.21850969f * a[2] - 0.14304817f * a[12] - 0.18467439f * a[14]; + tb = 0.21850969f * b[2] - 0.14304817f * b[12] - 0.18467439f * b[14]; + out[1] += ta * b[5] + tb * a[5]; + out[5] = ta * b[1] + tb * a[1]; + t = a[1] * b[5] + a[5] * b[1]; + out[2] = 0.21850969f * t; + out[12] = -0.14304817f * t; + out[14] = -0.18467439f * t; + + ta = 0.20230066f * a[11]; + tb = 0.20230066f * b[11]; + out[1] += ta * b[6] + tb * a[6]; + out[6] += ta * b[1] + tb * a[1]; + t = a[1] * b[6] + a[6] * b[1]; + out[11] = 0.20230066f * t; + + ta = 0.22617901f * a[9] + 0.05839917f * a[11]; + tb = 0.22617901f * b[9] + 0.05839917f * b[11]; + out[1] += ta * b[8] + tb * a[8]; + out[8] += ta * b[1] + tb * a[1]; + t = a[1] * b[8] + a[8] * b[1]; + out[9] = 0.22617901f * t; + out[11] += 0.05839917f * t; + + ta = 0.28209480f * a[0] + 0.25231326f * a[6]; + tb = 0.28209480f * b[0] + 0.25231326f * b[6]; + out[2] += ta * b[2] + tb * a[2]; + t = a[2] * b[2]; + out[0] += 0.28209480f * t; + out[6] += 0.25231326f * t; + + ta = 0.24776671f * a[12]; + tb = 0.24776671f * b[12]; + out[2] += ta * b[6] + tb * a[6]; + out[6] += ta * b[2] + tb * a[2]; + t = a[2] * b[6] + a[6] * b[2]; + out[12] += 0.24776671f * t; + + ta = 0.28209480f * a[0] - 0.12615663f * a[6] + 0.21850969f * a[8]; + tb = 0.28209480f * b[0] - 0.12615663f * b[6] + 0.21850969f * b[8]; + out[3] += ta * b[3] + tb * a[3]; + t = a[3] * b[3]; + out[0] += 0.28209480f * t; + out[6] -= 0.12615663f * t; + out[8] += 0.21850969f * t; + + ta = 0.20230066f * a[13]; + tb = 0.20230066f * b[13]; + out[3] += ta * b[6] + tb * a[6]; + out[6] += ta * b[3] + tb * a[3]; + t = a[3] * b[6] + a[6] * b[3]; + out[13] += 0.20230066f * t; + + ta = 0.21850969f * a[2] - 0.14304817f * a[12] + 0.18467439f * a[14]; + tb = 0.21850969f * b[2] - 0.14304817f * b[12] + 0.18467439f * b[14]; + out[3] += ta * b[7] + tb * a[7]; + out[7] = ta * b[3] + tb * a[3]; + t = a[3] * b[7] + a[7] * b[3]; + out[2] += 0.21850969f * t; + out[12] -= 0.14304817f * t; + out[14] += 0.18467439f * t; + + ta = -0.05839917f * a[13] + 0.22617901f * a[15]; + tb = -0.05839917f * b[13] + 0.22617901f * b[15]; + out[3] += ta * b[8] + tb * a[8]; + out[8] += ta * b[3] + tb * a[3]; + t = a[3] * b[8] + a[8] * b[3]; + out[13] -= 0.05839917f * t; + out[15] += 0.22617901f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[4] += ta * b[4] + tb * a[4]; + t = a[4] * b[4]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; + + ta = 0.15607835f * a[7]; + tb = 0.15607835f * b[7]; + out[4] += ta * b[5] + tb * a[5]; + out[5] += ta * b[4] + tb * a[4]; + t = a[4] * b[5] + a[5] * b[4]; + out[7] += 0.15607835f * t; + + ta = 0.22617901f * a[3] - 0.09403160f * a[13]; + tb = 0.22617901f * b[3] - 0.09403160f * b[13]; + out[4] += ta * b[9] + tb * a[9]; + out[9] += ta * b[4] + tb * a[4]; + t = a[4] * b[9] + a[9] * b[4]; + out[3] += 0.22617901f * t; + out[13] -= 0.09403160f * t; + + ta = 0.18467439f * a[2] - 0.18806319f * a[12]; + tb = 0.18467439f * b[2] - 0.18806319f * b[12]; + out[4] += ta * b[10] + tb * a[10]; + out[10] = ta * b[4] + tb * a[4]; + t = a[4] * b[10] + a[10] * b[4]; + out[2] += 0.18467439f * t; + out[12] -= 0.18806319f * t; + + ta = -0.05839917f * a[3] + 0.14567312f * a[13] + 0.09403160f * a[15]; + tb = -0.05839917f * b[3] + 0.14567312f * b[13] + 0.09403160f * b[15]; + out[4] += ta * b[11] + tb * a[11]; + out[11] += ta * b[4] + tb * a[4]; + t = a[4] * b[11] + a[11] * b[4]; + out[3] -= 0.05839917f * t; + out[13] += 0.14567312f * t; + out[15] += 0.09403160f * t; + + ta = 0.28209479f * a[0] + 0.09011186f * a[6] - 0.15607835f * a[8]; + tb = 0.28209479f * b[0] + 0.09011186f * b[6] - 0.15607835f * b[8]; + out[5] += ta * b[5] + tb * a[5]; + t = a[5] * b[5]; + out[0] += 0.28209479f * t; + out[6] += 0.09011186f * t; + out[8] -= 0.15607835f * t; + + ta = 0.14867701f * a[14]; + tb = 0.14867701f * b[14]; + out[5] += ta * b[9] + tb * a[9]; + out[9] += ta * b[5] + tb * a[5]; + t = a[5] * b[9] + a[9] * b[5]; + out[14] += 0.14867701f * t; + + ta = 0.18467439f * a[3] + 0.11516472f * a[13] - 0.14867701f * a[15]; + tb = 0.18467439f * b[3] + 0.11516472f * b[13] - 0.14867701f * b[15]; + out[5] += ta * b[10] + tb * a[10]; + out[10] += ta * b[5] + tb * a[5]; + t = a[5] * b[10] + a[10] * b[5]; + out[3] += 0.18467439f * t; + out[13] += 0.11516472f * t; + out[15] -= 0.14867701f * t; + + ta = 0.23359668f * a[2] + 0.05947080f * a[12] - 0.11516472f * a[14]; + tb = 0.23359668f * b[2] + 0.05947080f * b[12] - 0.11516472f * b[14]; + out[5] += ta * b[11] + tb * a[11]; + out[11] += ta * b[5] + tb * a[5]; + t = a[5] * b[11] + a[11] * b[5]; + out[2] += 0.23359668f * t; + out[12] += 0.05947080f * t; + out[14] -= 0.11516472f * t; + + ta = 0.28209479f * a[0]; + tb = 0.28209479f * b[0]; + out[6] += ta * b[6] + tb * a[6]; + t = a[6] * b[6]; + out[0] += 0.28209479f * t; + out[6] += 0.18022376f * t; + + ta = 0.09011186f * a[6] + 0.28209479f * a[0] + 0.15607835f * a[8]; + tb = 0.09011186f * b[6] + 0.28209479f * b[0] + 0.15607835f * b[8]; + out[7] += ta * b[7] + tb * a[7]; + t = a[7] * b[7]; + out[6] += 0.09011186f * t; + out[0] += 0.28209479f * t; + out[8] += 0.15607835f * t; + + ta = 0.14867701f * a[9] + 0.18467439f * a[1] + 0.11516472f * a[11]; + tb = 0.14867701f * b[9] + 0.18467439f * b[1] + 0.11516472f * b[11]; + out[7] += ta * b[10] + tb * a[10]; + out[10] += ta * b[7] + tb * a[7]; + t = a[7] * b[10] + a[10] * b[7]; + out[9] += 0.14867701f * t; + out[1] += 0.18467439f * t; + out[11] += 0.11516472f * t; + + ta = 0.05947080f * a[12] + 0.23359668f * a[2] + 0.11516472f * a[14]; + tb = 0.05947080f * b[12] + 0.23359668f * b[2] + 0.11516472f * b[14]; + out[7] += ta * b[13] + tb * a[13]; + out[13] += ta * b[7] + tb * a[7]; + t = a[7] * b[13] + a[13] * b[7]; + out[12] += 0.05947080f * t; + out[2] += 0.23359668f * t; + out[14] += 0.11516472f * t; + + ta = 0.14867701f * a[15]; + tb = 0.14867701f * b[15]; + out[7] += ta * b[14] + tb * a[14]; + out[14] += ta * b[7] + tb * a[7]; + t = a[7] * b[14] + a[14] * b[7]; + out[15] += 0.14867701f * t; + + ta = 0.28209479f * a[0] - 0.18022375f * a[6]; + tb = 0.28209479f * b[0] - 0.18022375f * b[6]; + out[8] += ta * b[8] + tb * a[8]; + t = a[8] * b[8]; + out[0] += 0.28209479f * t; + out[6] -= 0.18022375f * t; + + ta = -0.09403160f * a[11]; + tb = -0.09403160f * b[11]; + out[8] += ta * b[9] + tb * a[9]; + out[9] += ta * b[8] + tb * a[8]; + t = a[8] * b[9] + a[9] * b[8]; + out[11] -= 0.09403160f * t; + + ta = -0.09403160f * a[15]; + tb = -0.09403160f * b[15]; + out[8] += ta * b[13] + tb * a[13]; + out[13] += ta * b[8] + tb * a[8]; + t = a[8] * b[13] + a[13] * b[8]; + out[15] -= 0.09403160f * t; + + ta = 0.18467439f * a[2] - 0.18806319f * a[12]; + tb = 0.18467439f * b[2] - 0.18806319f * b[12]; + out[8] += ta * b[14] + tb * a[14]; + out[14] += ta * b[8] + tb * a[8]; + t = a[8] * b[14] + a[14] * b[8]; + out[2] += 0.18467439f * t; + out[12] -= 0.18806319f * t; + + ta = -0.21026104f * a[6] + 0.28209479f * a[0]; + tb = -0.21026104f * b[6] + 0.28209479f * b[0]; + out[9] += ta * b[9] + tb * a[9]; + t = a[9] * b[9]; + out[6] -= 0.21026104f * t; + out[0] += 0.28209479f * t; + + ta = 0.28209479f * a[0]; + tb = 0.28209479f * b[0]; + out[10] += ta * b[10] + tb * a[10]; + t = a[10] * b[10]; + out[0] += 0.28209479f * t; + + ta = 0.28209479f * a[0] + 0.12615663f * a[6] - 0.14567312f * a[8]; + tb = 0.28209479f * b[0] + 0.12615663f * b[6] - 0.14567312f * b[8]; + out[11] += ta * b[11] + tb * a[11]; + t = a[11] * b[11]; + out[0] += 0.28209479f * t; + out[6] += 0.12615663f * t; + out[8] -= 0.14567312f * t; + + ta = 0.28209479f * a[0] + 0.16820885f * a[6]; + tb = 0.28209479f * b[0] + 0.16820885f * b[6]; + out[12] += ta * b[12] + tb * a[12]; + t = a[12] * b[12]; + out[0] += 0.28209479f * t; + out[6] += 0.16820885f * t; + + ta = 0.28209479f * a[0] + 0.14567312f * a[8] + 0.12615663f * a[6]; + tb = 0.28209479f * b[0] + 0.14567312f * b[8] + 0.12615663f * b[6]; + out[13] += ta * b[13] + tb * a[13]; + t = a[13] * b[13]; + out[0] += 0.28209479f * t; + out[8] += 0.14567312f * t; + out[6] += 0.12615663f * t; + + ta = 0.28209479f * a[0]; + tb = 0.28209479f * b[0]; + out[14] += ta * b[14] + tb * a[14]; + t = a[14] * b[14]; + out[0] += 0.28209479f * t; + + ta = 0.28209479f * a[0] - 0.21026104f * a[6]; + tb = 0.28209479f * b[0] - 0.21026104f * b[6]; + out[15] += ta * b[15] + tb * a[15]; + t = a[15] * b[15]; + out[0] += 0.28209479f * t; + out[6] -= 0.21026104f * t; +} +//+------------------------------------------------------------------+ +//| rotate_X | +//+------------------------------------------------------------------+ +void rotate_X(float &out[], uint order, float a, float &in[]) { + out[0] = in[0]; + out[1] = a * in[2]; + out[2] = -a * in[1]; + out[3] = in[3]; + out[4] = a * in[7]; + out[5] = -in[5]; + out[6] = -0.5f * in[6] - 0.8660253882f * in[8]; + out[7] = -a * in[4]; + out[8] = -0.8660253882f * in[6] + 0.5f * in[8]; + out[9] = -a * 0.7905694842f * in[12] + a * 0.6123724580f * in[14]; + out[10] = -in[10]; + out[11] = -a * 0.6123724580f * in[12] - a * 0.7905694842f * in[14]; + out[12] = a * 0.7905694842f * in[9] + a * 0.6123724580f * in[11]; + out[13] = -0.25f * in[13] - 0.9682458639f * in[15]; + out[14] = -a * 0.6123724580f * in[9] + a * 0.7905694842f * in[11]; + out[15] = -0.9682458639f * in[13] + 0.25f * in[15]; + if (order == 4) return; + + out[16] = -a * 0.9354143739f * in[21] + a * 0.3535533845f * in[23]; + out[17] = -0.75f * in[17] + 0.6614378095f * in[19]; + out[18] = -a * 0.3535533845f * in[21] - a * 0.9354143739f * in[23]; + out[19] = 0.6614378095f * in[17] + 0.75f * in[19]; + out[20] = 0.375f * in[20] + 0.5590170026f * in[22] + 0.7395099998f * in[24]; + out[21] = a * 0.9354143739f * in[16] + a * 0.3535533845f * in[18]; + out[22] = 0.5590170026f * in[20] + 0.5f * in[22] - 0.6614378691f * in[24]; + out[23] = -a * 0.3535533845f * in[16] + a * 0.9354143739f * in[18]; + out[24] = 0.7395099998f * in[20] - 0.6614378691f * in[22] + 0.125f * in[24]; + if (order == 5) return; + + out[25] = a * 0.7015607357f * in[30] - a * 0.6846531630f * in[32] + a * 0.1976423711f * in[34]; + out[26] = -0.5f * in[26] + 0.8660253882f * in[28]; + out[27] = a * 0.5229125023f * in[30] + a * 0.3061861992f * in[32] - a * 0.7954951525f * in[34]; + out[28] = 0.8660253882f * in[26] + 0.5f * in[28]; + out[29] = a * 0.4841229022f * in[30] + a * 0.6614378691f * in[32] + a * 0.5728219748f * in[34]; + out[30] = -a * 0.7015607357f * in[25] - a * 0.5229125023f * in[27] - a * 0.4841229022f * in[29]; + out[31] = 0.125f * in[31] + 0.4050463140f * in[33] + 0.9057110548f * in[35]; + out[32] = a * 0.6846531630f * in[25] - a * 0.3061861992f * in[27] - a * 0.6614378691f * in[29]; + out[33] = 0.4050463140f * in[31] + 0.8125f * in[33] - 0.4192627370f * in[35]; + out[34] = -a * 0.1976423711f * in[25] + a * 0.7954951525f * in[27] - a * 0.5728219748f * in[29]; + out[35] = 0.9057110548f * in[31] - 0.4192627370f * in[33] + 0.0624999329f * in[35]; +} +//+------------------------------------------------------------------+ +//| Rotates the spherical harmonic (SH) vector by the given matrix. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) | +//| is stored at memory location l^2 + m + l, where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHRotate(float &out[], int order, const DXMatrix &matrix, const float &in[]) { + float alpha, beta, gamma, sinb, temp[36], temp1[36]; + out[0] = in[0]; + + if ((order > DXSH_MAXORDER) || (order < DXSH_MINORDER)) return; + + if (order <= 3) { + out[1] = matrix.m[1][1] * in[1] - matrix.m[2][1] * in[2] + matrix.m[0][1] * in[3]; + out[2] = -matrix.m[1][2] * in[1] + matrix.m[2][2] * in[2] - matrix.m[0][2] * in[3]; + out[3] = matrix.m[1][0] * in[1] - matrix.m[2][0] * in[2] + matrix.m[0][0] * in[3]; + + if (order == 3) { + float coeff[12] = {}; + coeff[0] = matrix.m[1][0] * matrix.m[0][0]; + coeff[1] = matrix.m[1][1] * matrix.m[0][1]; + coeff[2] = matrix.m[1][1] * matrix.m[2][1]; + coeff[3] = matrix.m[1][0] * matrix.m[2][0]; + coeff[4] = matrix.m[2][0] * matrix.m[2][0]; + coeff[5] = matrix.m[2][1] * matrix.m[2][1]; + coeff[6] = matrix.m[0][0] * matrix.m[2][0]; + coeff[7] = matrix.m[0][1] * matrix.m[2][1]; + coeff[8] = matrix.m[0][1] * matrix.m[0][1]; + coeff[9] = matrix.m[1][0] * matrix.m[1][0]; + coeff[10] = matrix.m[1][1] * matrix.m[1][1]; + coeff[11] = matrix.m[0][0] * matrix.m[0][0]; + + out[4] = (matrix.m[1][1] * matrix.m[0][0] + matrix.m[0][1] * matrix.m[1][0]) * in[4]; + out[4] -= (matrix.m[1][0] * matrix.m[2][1] + matrix.m[1][1] * matrix.m[2][0]) * in[5]; + out[4] += 1.7320508076f * matrix.m[2][0] * matrix.m[2][1] * in[6]; + out[4] -= (matrix.m[0][1] * matrix.m[2][0] + matrix.m[0][0] * matrix.m[2][1]) * in[7]; + out[4] += (matrix.m[0][0] * matrix.m[0][1] - matrix.m[1][0] * matrix.m[1][1]) * in[8]; + + out[5] = (matrix.m[1][1] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][1]) * in[5]; + out[5] -= (matrix.m[1][1] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][1]) * in[4]; + out[5] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][1] * in[6]; + out[5] += (matrix.m[0][2] * matrix.m[2][1] + matrix.m[0][1] * matrix.m[2][2]) * in[7]; + out[5] -= (matrix.m[0][1] * matrix.m[0][2] - matrix.m[1][1] * matrix.m[1][2]) * in[8]; + + out[6] = (matrix.m[2][2] * matrix.m[2][2] - 0.5f * (coeff[4] + coeff[5])) * in[6]; + out[6] -= (0.5773502692f * (coeff[0] + coeff[1]) - 1.1547005384f * matrix.m[1][2] * matrix.m[0][2]) * in[4]; + out[6] += (0.5773502692f * (coeff[2] + coeff[3]) - 1.1547005384f * matrix.m[1][2] * matrix.m[2][2]) * in[5]; + out[6] += (0.5773502692f * (coeff[6] + coeff[7]) - 1.1547005384f * matrix.m[0][2] * matrix.m[2][2]) * in[7]; + out[6] += (0.2886751347f * (coeff[9] - coeff[8] + coeff[10] - coeff[11]) - + 0.5773502692f * (matrix.m[1][2] * matrix.m[1][2] - matrix.m[0][2] * matrix.m[0][2])) * + in[8]; + + out[7] = (matrix.m[0][0] * matrix.m[2][2] + matrix.m[0][2] * matrix.m[2][0]) * in[7]; + out[7] -= (matrix.m[1][0] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][0]) * in[4]; + out[7] += (matrix.m[1][0] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][0]) * in[5]; + out[7] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][0] * in[6]; + out[7] -= (matrix.m[0][0] * matrix.m[0][2] - matrix.m[1][0] * matrix.m[1][2]) * in[8]; + + out[8] = 0.5f * (coeff[11] - coeff[8] - coeff[9] + coeff[10]) * in[8]; + out[8] += (coeff[0] - coeff[1]) * in[4]; + out[8] += (coeff[2] - coeff[3]) * in[5]; + out[8] += 0.86602540f * (coeff[4] - coeff[5]) * in[6]; + out[8] += (coeff[7] - coeff[6]) * in[7]; + } + return; + } + + if ((float)fabs(matrix.m[2][2]) != 1.0f) { + sinb = (float)sqrt(1.0f - matrix.m[2][2] * matrix.m[2][2]); + alpha = (float)atan2(matrix.m[2][1] / sinb, matrix.m[2][0] / sinb); + beta = (float)atan2(sinb, matrix.m[2][2]); + gamma = (float)atan2(matrix.m[1][2] / sinb, -matrix.m[0][2] / sinb); + } else { + alpha = (float)atan2(matrix.m[0][1], matrix.m[0][0]); + beta = 0.0f; + gamma = 0.0f; + } + //--- + DXSHRotateZ(temp, order, gamma, in); + rotate_X(temp1, order, 1.0f, temp); + DXSHRotateZ(temp, order, beta, temp1); + rotate_X(temp1, order, -1.0f, temp); + DXSHRotateZ(out, order, alpha, temp1); +} +//+------------------------------------------------------------------+ +//| Rotates the spherical harmonic (SH) vector | +//| in the z-axis by the given angle. | +//+------------------------------------------------------------------+ +//| Each coefficient of the basis function Y(l,m) | +//| is stored at memory location l^2 + m + l, where: | +//| l is the degree of the basis function. | +//| m is the basis function index for the given l value | +//| and ranges from -l to l, inclusive. | +//+------------------------------------------------------------------+ +void DXSHRotateZ(float &out[], int order, float angle, const float &in[]) { + int sum = 0; + float c[5], s[5]; + order = (int)fmin(fmax(order, DXSH_MINORDER), DXSH_MAXORDER); + out[0] = in[0]; + //--- + for (int i = 1; i < order; i++) { + c[i - 1] = (float)cos(i * angle); + s[i - 1] = (float)sin(i * angle); + sum += i * 2; + //--- + out[sum - i] = c[i - 1] * in[sum - i]; + out[sum - i] += s[i - 1] * in[sum + i]; + for (int j = i - 1; j > 0; j--) { + out[sum - j] = 0.0f; + out[sum - j] = c[j - 1] * in[sum - j]; + out[sum - j] += s[j - 1] * in[sum + j]; + } + out[sum] = in[sum]; + //--- + for (int j = 1; j < i; j++) { + out[sum + j] = 0.0f; + out[sum + j] = -s[j - 1] * in[sum - j]; + out[sum + j] += c[j - 1] * in[sum + j]; + } + out[sum + i] = -s[i - 1] * in[sum - i]; + out[sum + i] += c[i - 1] * in[sum + i]; + } +} +//+------------------------------------------------------------------+ +//| Scales a spherical harmonic (SH) vector; | +//| in other words, out[i] = a[i]*scale. | +//+------------------------------------------------------------------+ +void DXSHScale(float &out[], int order, const float &a[], const float scale) { + for (int i = 0; i < order * order; i++) out[i] = a[i] * scale; +} +//+---------------------------------------------------------------------+ +//| Interpolates y0 to y1 according to value from 0.0 to 1.0 | +//+---------------------------------------------------------------------+ +float DXScalarLerp(const float val1, const float val2, float s) { return ((1 - s) * val1 + s * val2); } +//+---------------------------------------------------------------------+ +//| Interpolates y0 to y1 according to value from 0.0 to 1.0 | +//+---------------------------------------------------------------------+ +float DXScalarBiasScale(const float val, const float bias, const float scale) { return ((val + bias) * scale); } +//+------------------------------------------------------------------+ diff --git a/3D/Mesh.h b/3D/Mesh.h new file mode 100644 index 000000000..2d28ddaf9 --- /dev/null +++ b/3D/Mesh.h @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics mesh. + */ + +#include "../Dict.mqh" +#include "../Refs.mqh" +#include "../Util.h" +#include "Face.h" +#include "IndexBuffer.h" +#include "Math.h" +#include "VertexBuffer.h" + +class Device; + +#define GFX_MESH_LOOKUP_PRECISION 0.001f + +// Point with a key for faster vertices' lookup by their position. +template +struct PointEntry { + T point; + long key; + + PointEntry() {} + + PointEntry(const T& _point) { + point = _point; + key = MakeKey(_point.Position[0], _point.Position[1], _point.Position[2]); + } + + bool operator==(const PointEntry& _r) { + return key == MakeKey(_r.point.Position[0], _r.point.Position[1], _r.point.Position[2]); + } + + static long MakeKey(float x, float y, float z) { + return long(x / GFX_MESH_LOOKUP_PRECISION) + 4194304 * long(y / GFX_MESH_LOOKUP_PRECISION) + + 17592186044416 * long(z / GFX_MESH_LOOKUP_PRECISION); + } +}; + +template +class Mesh : public Dynamic { + Ref vbuff; + Ref ibuff; + Face faces[]; + + public: + /** + * Constructor. + */ + Mesh() {} + + /** + * Adds a single 3 or 4-vertex face. + */ + void AddFace(Face& face) { Util::ArrayPush(faces, face, 16); } + + /** + * Returns vertex and index buffers for this mesh. + * + * @todo Buffers should be invalidated if mesh has changed. + */ + bool GetBuffers(Device* _device, VertexBuffer*& _vbuff, IndexBuffer*& _ibuff) { + if (vbuff.IsSet() && ibuff.IsSet()) { + _vbuff = vbuff.Ptr(); + _ibuff = ibuff.Ptr(); + return true; + } + + DictStruct> _points; + T _vertices[]; + unsigned int _indices[]; + int i, k; + + for (i = 0; i < ArraySize(faces); ++i) { + Face _face = faces[i]; + int _face_indices[4]; + + // Adding first triangle. + for (k = 0; k < 3; ++k) { + PointEntry point1(_face.points[k]); + _face_indices[k] = _points.IndexOf(point1); + + if (_face_indices[k] == -1) { + // Point not yet added. + _points.Push(point1); + _face_indices[k] = (int)_points.Size() - 1; + } + + Util::ArrayPush(_indices, _face_indices[k]); + } + + // Adding second triangle if needed. + if ((_face.flags & FACE_FLAGS_QUAD) == FACE_FLAGS_QUAD) { + PointEntry point2(_face.points[3]); + _face_indices[3] = _points.IndexOf(point2); + + if (_face_indices[3] == -1) { + // Point not yet added. + _points.Push(point2); + _face_indices[3] = (int)_points.Size() - 1; + } + + Util::ArrayPush(_indices, _face_indices[0]); + Util::ArrayPush(_indices, _face_indices[2]); + Util::ArrayPush(_indices, _face_indices[3]); + } + } + + ArrayResize(_vertices, _points.Size()); + + for (DictIteratorBase> iter(_points.Begin()); iter.IsValid(); ++iter) { + _vertices[iter.Index()] = iter.Value().point; + } + + string _s_vertices = "["; + + for (i = 0; i < ArraySize(_vertices); ++i) { + _s_vertices += "["; + _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position[0]) + ", " + + DoubleToString(_vertices[i].Position[1]) + "," + DoubleToString(_vertices[i].Position[2]) + " | "; + _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color[0]) + ", " + DoubleToString(_vertices[i].Color[1]) + + "," + DoubleToString(_vertices[i].Color[2]) + "," + DoubleToString(_vertices[i].Color[3]); + _s_vertices += "]"; + if (i != ArraySize(_vertices) - 1) { + _s_vertices += ", "; + } + } + + _s_vertices += "]"; + + string _s_indices = "["; + + for (i = 0; i < ArraySize(_indices); ++i) { + _s_indices += DoubleToString(_indices[i]); + if (i != ArraySize(_indices) - 1) { + _s_indices += ", "; + } + } + + _s_indices += "]"; + + Print("Vertices: ", _s_vertices); + Print("Indices: ", _s_indices); + + vbuff = _vbuff = _device.VertexBuffer(_vertices); + ibuff = _ibuff = _device.IndexBuffer(_indices); + return true; + } +}; \ No newline at end of file diff --git a/3D/Shader.h b/3D/Shader.h index 1ef91bd65..1500a1430 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -1,5 +1,33 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics shader. + */ + #include "../Refs.mqh" +// Shader type. enum ENUM_SHADER_TYPE { SHADER_TYPE_VS, SHADER_TYPE_PS, @@ -10,6 +38,7 @@ class MTDXShader; enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; +// Vertex layout used for Vertex Shaders. struct ShaderVertexLayout { string name; unsigned int index; @@ -24,6 +53,7 @@ struct ShaderVertexLayout { * Unified vertex/pixel shader. */ class Shader : public Dynamic { + // Reference to graphics device. WeakRef device; public: @@ -36,19 +66,24 @@ class Shader : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } - - template + + /** + * Sets custom input buffer for shader. + */ + template void SetCBuffer(const X& data) { // Unfortunately we can't make this method virtual. if (dynamic_cast(&this) != NULL) { // MT5's DirectX. Print("Setting CBuffer data for MT5"); ((MTDXShader*)&this).SetCBuffer(data); - } - else { + } else { Alert("Unsupported cbuffer device target"); } } - + + /** + * Selectes shader to be used by graphics device for rendering. + */ virtual void Select() = NULL; }; \ No newline at end of file diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h index cf3f600f4..8c979b384 100644 --- a/3D/VertexBuffer.h +++ b/3D/VertexBuffer.h @@ -1,6 +1,34 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Generic graphics vertex buffer. + */ + #include "../Refs.mqh" class VertexBuffer : public Dynamic { + // Reference to graphics device. WeakRef device; public: @@ -13,6 +41,6 @@ class VertexBuffer : public Dynamic { * Returns base graphics device. */ Device* GetDevice() { return device.Ptr(); } - + virtual void Select() = NULL; }; \ No newline at end of file diff --git a/Dict.mqh b/Dict.mqh index 0e2bf1e10..56c6efc58 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -152,6 +152,20 @@ class Dict : public DictBase { return slot.value == value; } + /** + * Returns index of dictionary's value or -1 if value doesn't exist. + */ + template <> + int IndexOf(V& value) { + for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + if (i.Value() == value) { + return (int)i.Index(); + } + } + + return -1; + } + protected: /** * Inserts value into given array of DictSlots. diff --git a/DictObject.mqh b/DictObject.mqh index ac35f8f25..83fa62339 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -158,6 +158,20 @@ class DictObject : public DictBase { return slot.value == value; } + /** + * Returns index of dictionary's value or -1 if value doesn't exist. + */ + template <> + int IndexOf(V& value) { + for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + if (i.Value() == value) { + return (int)i.Index(); + } + } + + return -1; + } + protected: /** * Inserts value into given array of DictSlots. diff --git a/DictStruct.mqh b/DictStruct.mqh index f3609c5cd..f1137f529 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -195,6 +195,20 @@ class DictStruct : public DictBase { return slot.value == value; } + /** + * Returns index of dictionary's value or -1 if value doesn't exist. + */ + template <> + int IndexOf(const V& value) { + for (DictIteratorBase i(Begin()); i.IsValid(); ++i) { + if (i.Value() == value) { + return (int)i.Index(); + } + } + + return -1; + } + protected: /** * Inserts value into given array of DictSlots. diff --git a/Util.h b/Util.h new file mode 100644 index 000000000..e562d1955 --- /dev/null +++ b/Util.h @@ -0,0 +1,46 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* + * @file + * Utility methods. + */ + +class Util { + /** + * Resizes native array and reserves space for further items by some fixed step. + */ + template + static void ArrayResize(T& _array[], int _new_size, int _resize_pool = 32) { + ::ArrayResize(_array, _new_size, (_new_size / _resize_pool + 1) * _resize_pool); + } + + /** + * Pushes item into the native array and reserves space for further items by some fixed step. + */ + template + static int ArrayPush(T& _array[], const V& _value, int _resize_pool = 32) { + Util::ArrayResize(_array, ArraySize(_array) + 1, _resize_pool); + _array[ArraySize(_array) - 1] = _value; + return ArraySize(_array) - 1; + } +}; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 9a20bfd27..6211ca9ac 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -24,111 +24,110 @@ * Test functionality of 3D visualization classes. */ +#ifdef __MQL5__ + // Resources. #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; // Includes. -#include "../3D/Frontends/MT5Frontend.h" +#include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" #include "../3D/Devices/MTDX/MTDXIndexBuffer.h" #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" +#include "../3D/Frontends/MT5Frontend.h" #include "../Test.mqh" -int OnStart() { - return OnInit(); -} +// int OnStart() { return OnInit(); } struct Vertex { float Position[3]; float Color[4]; + + Vertex() { + Color[0] = 1.0f / 65535 * rand(); + Color[1] = 1.0f / 65535 * rand(); + Color[2] = 1.0f / 65535 * rand(); + Color[3] = 1.0f; + } }; const ShaderVertexLayout VertexLayout[] = { - { "POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0 }, - { "COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float)*3 }, + {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, + {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 3}, }; -struct PSCBuffer -{ +struct PSCBuffer { DXMatrix world; DXMatrix view; DXMatrix proj; }; /** - * Implements OnStart(). + * Implements Oninit(). */ int OnInit() { Ref gfx_ptr = new MTDXDevice(); Device* gfx = gfx_ptr.Ptr(); - + gfx.Start(new MT5Frontend()); - + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); Ref _shader_p = gfx.PixelShader(ShaderSourcePS); - - Vertex vertices[]= { - { - {-0.5, -0.5, 0.0}, - { 1.0, 0.0, 0.0, 1.0}, - }, - { - {-0.5, 0.5, 0.0}, - { 0.0, 0.1, 0.0, 1.0}, - }, - { - { 0.5, 0.5, 0.0}, - { 0.0, 0.0, 1.0, 1.0}, - }, - { - { 0.5, -0.5, 0.0}, - { 0.5, 0.5, 1.0, 1.0}, - } - }; - - unsigned int indices[] = { - 0, 1, 2, - 2, 3, 0 - }; - - Ref _vbuff = gfx.VertexBuffer(vertices); - Ref _ibuff = gfx.IndexBuffer(indices); - + + Ref> _mesh = new Cube(0, 0, 0, 10, 20, 30); + unsigned int _rand_color = rand() * 1256; - - while (!IsStopped()) - { + + while (!IsStopped()) { if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { break; } - + gfx.Begin(_rand_color); - + PSCBuffer psCBuffer; - + DXMatrixIdentity(psCBuffer.world); DXMatrixIdentity(psCBuffer.view); - DXMatrixIdentity(psCBuffer.proj); - DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI/6, 1.5f, 0.1f, 100.0f); - DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -5), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); - - DXMatrix rotate; - static float x = 0; x += 0.1f; - DXMatrixRotationZ(rotate, x); - - DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate); - - + DXMatrixIdentity(psCBuffer.proj); + DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI / 6, 1.5f, 0.1f, 1000.0f); + DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -125), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); + + DXMatrix rotate_x; + static float x = 0; + x += 0.03f; + DXMatrixRotationX(rotate_x, x); + + DXMatrix rotate_y; + static float y = 0; + y += 0.01f; + DXMatrixRotationY(rotate_y, y); + + DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_x); + DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_y); + _shader_v.Ptr().SetCBuffer(psCBuffer); gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); - gfx.Render(_vbuff.Ptr(), _ibuff.Ptr()); - + + gfx.Render(_mesh.Ptr()); + gfx.End(); + + // break; } gfx.Stop(); return (INIT_SUCCEEDED); } + +#else + +int OnInit() { + // Nothing to test in non-MT5 environment. + return (INIT_SUCCEEDED); +} + +#endif \ No newline at end of file From 217cebb0ecc8db0d60d3099e0ead703d882e1ed7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 29 Apr 2021 21:43:12 +0200 Subject: [PATCH 17/97] WIP. Added lighting and camera setting. --- 3D/Chart3D.h | 52 ++++++++++++++++++++ 3D/Cube.h | 2 +- 3D/Device.h | 70 +++++++++++++++++++++++++-- 3D/Devices/MTDX/MTDXDevice.h | 2 +- 3D/Devices/MTDX/MTDXShader.h | 44 ++++++++++++++++- 3D/Face.h | 68 ++++++++++++++------------ 3D/Frontends/MT5Frontend.h | 5 +- 3D/Mesh.h | 72 +++++++++++++++++++--------- 3D/Shader.h | 11 +++++ 3D/Shaders/chart3d.ps.hlsl | 0 3D/Shaders/chart3d.vs.hlsl | 0 3D/TSR.h | 61 ++++++++++++++++++++++++ Util.h | 10 ++++ tests/3D/Shaders/pixel.hlsl | 9 ++-- tests/3D/Shaders/vertex.hlsl | 24 ++++++---- tests/3DTest.mq5 | 92 ++++++++++++++++++------------------ 16 files changed, 401 insertions(+), 121 deletions(-) create mode 100644 3D/Chart3D.h create mode 100644 3D/Shaders/chart3d.ps.hlsl create mode 100644 3D/Shaders/chart3d.vs.hlsl create mode 100644 3D/TSR.h diff --git a/3D/Chart3D.h b/3D/Chart3D.h new file mode 100644 index 000000000..bf093884e --- /dev/null +++ b/3D/Chart3D.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * 3D Chart. + */ + +#include "../Refs.mqh" +#include "Cube.h" +#include "Device.h" + +// Resources. +#resource "Shaders/chart3d.ps.hlsl" as string Chart3DShaderSourcePS; +#resource "Shaders/chart3d.vs.hlsl" as string Chart3DShaderSourceVS; + +class Chart3D : public Dynamic { + // Reference to graphics device. + WeakRef device; + + public: + /** + * Constructor. + */ + VertexBuffer(Device* _device) { device = _device; } + + /** + * Returns base graphics device. + */ + Device* GetDevice() { return device.Ptr(); } + + virtual void Select() = NULL; +}; \ No newline at end of file diff --git a/3D/Cube.h b/3D/Cube.h index b11194300..e9ea4d095 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -34,7 +34,7 @@ template class Cube : public Mesh { public: - Cube(float x = 0.0f, float y = 0.0f, float z = 0.0f, float size_x = 1.0f, float size_y = 1.0f, float size_z = 1.0f) { + Cube(float size_x, float size_y, float size_z, float x = 0.0f, float y = 0.0f, float z = 0.0f) { float half_x = size_x / 2; float half_y = size_y / 2; float half_z = size_z / 2; diff --git a/3D/Device.h b/3D/Device.h index e9b259e0a..6d0777244 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -26,6 +26,7 @@ */ #include "../Refs.mqh" +#include "../Util.h" #include "Frontend.h" #include "IndexBuffer.h" #include "Math.h" @@ -42,6 +43,11 @@ class Device : public Dynamic { protected: int context; Ref frontend; + DXMatrix mtx_stack[]; + DXMatrix mtx_world; + DXMatrix mtx_view; + DXMatrix mtx_projection; + DXVector3 lightdir; public: /** @@ -49,16 +55,29 @@ class Device : public Dynamic { */ bool Start(Frontend* _frontend) { frontend = _frontend; + DXMatrixIdentity(mtx_world); + DXMatrixIdentity(mtx_view); + DXMatrixIdentity(mtx_projection); + TSR _identity; + PushTransform(_identity); + lightdir = DXVector3(-0.2f, 0.2f, 1.0f); return Init(_frontend); } + void PushTransform(const TSR& tsr) { + mtx_world = tsr.ToMatrix(); + Util::ArrayPush(mtx_stack, mtx_world); + } + + void PopTransform() { mtx_world = Util::ArrayPop(mtx_stack); } + /** * Begins render loop. */ Device* Begin(unsigned int clear_color = 0) { frontend.Ptr().RenderBegin(context); - ClearDepth(); Clear(clear_color); + ClearDepth(); RenderBegin(); return &this; } @@ -142,17 +161,30 @@ class Device : public Dynamic { /** * Renders vertex buffer with optional point indices. */ - virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; + void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { RenderBuffers(_vertices, _indices); } + + /** + * Renders vertex buffer with optional point indices. + */ + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) = NULL; /** * Renders given mesh. */ template - void Render(Mesh* _mesh) { + void Render(Mesh* _mesh, Shader* _vs = NULL, Shader* _ps = NULL) { Print("Rendering mesh"); VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); + if (_vs != NULL) { + SetShader(_vs); + } + if (_ps != NULL) { + SetShader(_ps); + } + // Setting MVP matrices. + Render(_vertices, _indices); } @@ -169,6 +201,38 @@ class Device : public Dynamic { _shader2.Select(); } + /** + * Returns front-end's viewport width. + */ + int Width() { return frontend.Ptr().Width(); } + + /** + * Returns front-end's viewport height. + */ + int Height() { return frontend.Ptr().Height(); } + + void SetCameraOrtho3D() { DXMatrixOrthoRH(mtx_view, Width(), Height(), -10000, 10000); } + + DXMatrix GetWorldMatrix() { return mtx_world; } + + void SetWorldMatrix(DXMatrix& _matrix) { mtx_world = _matrix; } + + DXMatrix GetViewMatrix() { return mtx_view; } + + void SetViewMatrix(DXMatrix& _matrix) { mtx_view = _matrix; } + + DXMatrix GetProjectionMatrix() { return mtx_projection; } + + void SetProjectionMatrix(DXMatrix& _matrix) { mtx_projection = _matrix; } + + DXVector3 GetLightDirection() { return lightdir; } + + void SetLightDirection(float x, float y, float z) { + lightdir.x = x; + lightdir.y = y; + lightdir.z = z; + } + protected: /** * Initializes graphics device. diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 5794160c2..96eddc266 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -126,7 +126,7 @@ class MTDXDevice : public Device { /** * */ - virtual void Render(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { + virtual void RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) { DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _vertices.Select(); if (_indices == NULL) { diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index 1fcf90a68..eacbfc484 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -31,7 +31,12 @@ class MTDXShader : public Shader { // DX context handle. int handle; - // DX C-Buffer handle. + // DX MVP's C-Buffer handle (register b0). + int cbuffer_mvp_handle; + + MVPBuffer mvp_buffer; + + // DX C-Buffer handle. (register b1). int cbuffer_handle; public: @@ -40,6 +45,15 @@ class MTDXShader : public Shader { */ MTDXShader(Device* _device) : Shader(_device) {} + /** + * Destructor. + */ + ~MTDXShader() { + DXRelease(cbuffer_handle); + DXRelease(cbuffer_mvp_handle); + DXRelease(handle); + } + /** * Creates a shader. */ @@ -53,6 +67,10 @@ class MTDXShader : public Shader { cbuffer_handle = 0; + // Creating MVP buffer. + cbuffer_mvp_handle = DXInputCreate(GetDevice().Context(), sizeof(MVPBuffer)); + Print("DXInputCreate (mvp): LastError: ", GetLastError()); + return true; } @@ -135,5 +153,27 @@ class MTDXShader : public Shader { /** * Selectes shader to be used by graphics device for rendering. */ - virtual void Select() { DXShaderSet(GetDevice().Context(), handle); } + virtual void Select() { + // Setting MVP transform. + mvp_buffer.world = GetDevice().GetWorldMatrix(); + mvp_buffer.view = GetDevice().GetViewMatrix(); + mvp_buffer.projection = GetDevice().GetProjectionMatrix(); + mvp_buffer.lightdir = GetDevice().GetLightDirection(); + + if (cbuffer_handle == 0) { + int _input_handles[1]; + _input_handles[0] = cbuffer_mvp_handle; + DXShaderInputsSet(handle, _input_handles); + } else { + int _input_handles[2]; + _input_handles[0] = cbuffer_mvp_handle; + _input_handles[1] = cbuffer_handle; + DXShaderInputsSet(handle, _input_handles); + } + + Print("DXShaderInputsSet: LastError: ", GetLastError()); + + DXInputSet(cbuffer_mvp_handle, mvp_buffer); + DXShaderSet(GetDevice().Context(), handle); + } }; \ No newline at end of file diff --git a/3D/Face.h b/3D/Face.h index c8a8ee9c9..7f7ad38af 100644 --- a/3D/Face.h +++ b/3D/Face.h @@ -44,30 +44,20 @@ struct Face { */ Face() { flags = FACE_FLAGS_NONE; } - /** - * Copy constructor. - */ - Face(const Face& r) { - flags = r.flags; - for (int p = 0; p < 4; ++p) { - points[p] = r.points[p]; - } - } - /** * Constructor. */ Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) { flags = FACE_FLAGS_TRIANGLE; - points[0].Position[0] = x1; - points[0].Position[1] = y1; - points[0].Position[2] = z1; - points[1].Position[0] = x2; - points[1].Position[1] = y2; - points[1].Position[2] = z2; - points[2].Position[0] = x3; - points[2].Position[1] = y3; - points[2].Position[2] = z3; + points[0].Position.x = x1; + points[0].Position.y = y1; + points[0].Position.z = z1; + points[1].Position.x = x2; + points[1].Position.y = y2; + points[1].Position.z = z2; + points[2].Position.x = x3; + points[2].Position.y = y3; + points[2].Position.z = z3; } /** @@ -76,17 +66,33 @@ struct Face { Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4) { flags = FACE_FLAGS_QUAD; - points[0].Position[0] = x1; - points[0].Position[1] = y1; - points[0].Position[2] = z1; - points[1].Position[0] = x2; - points[1].Position[1] = y2; - points[1].Position[2] = z2; - points[2].Position[0] = x3; - points[2].Position[1] = y3; - points[2].Position[2] = z3; - points[3].Position[0] = x4; - points[3].Position[1] = y4; - points[3].Position[2] = z4; + points[0].Position.x = x1; + points[0].Position.y = y1; + points[0].Position.z = z1; + points[1].Position.x = x2; + points[1].Position.y = y2; + points[1].Position.z = z2; + points[2].Position.x = x3; + points[2].Position.y = y3; + points[2].Position.z = z3; + points[3].Position.x = x4; + points[3].Position.y = y4; + points[3].Position.z = z4; + } + + void UpdateNormal() { + DXVector3 _normal, _v1, _v2; + + DXVec3Subtract(_v1, points[1].Position, points[0].Position); + DXVec3Subtract(_v2, points[2].Position, points[0].Position); + + DXVec3Cross(_normal, _v1, _v2); + DXVec3Normalize(_normal, _normal); + + // Print("cross = ", _normal.x, ", ", _normal.y, ", ", _normal.z); + + for (int i = 0; i < 4; ++i) { + points[i].Normal = _normal; + } } }; \ No newline at end of file diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 3d75592ec..357b4266a 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -75,6 +75,7 @@ class MT5Frontend : public Frontend { ResourceFree(resname); ObjectDelete(0, objname); ChartSetInteger(0, CHART_SHOW, true); + ChartRedraw(); return true; } @@ -88,7 +89,7 @@ class MT5Frontend : public Frontend { ArrayResize(image, Width() * Height()); Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); - ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); Print("ResourceCreate: LastError: ", GetLastError()); last_width = Width(); @@ -120,7 +121,7 @@ class MT5Frontend : public Frontend { Print("MT5Frontend: DXContextGetColors()"); DXContextGetColors(context, image); Print("DXContextGetColors: LastError: ", GetLastError()); - ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_XRGB_NOALPHA); + ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); Print("ResourceCreate: LastError: ", GetLastError()); ChartRedraw(); Sleep(5); diff --git a/3D/Mesh.h b/3D/Mesh.h index 2d28ddaf9..d09d6ab1a 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -31,6 +31,7 @@ #include "Face.h" #include "IndexBuffer.h" #include "Math.h" +#include "TSR.h" #include "VertexBuffer.h" class Device; @@ -47,11 +48,11 @@ struct PointEntry { PointEntry(const T& _point) { point = _point; - key = MakeKey(_point.Position[0], _point.Position[1], _point.Position[2]); + key = MakeKey(_point.Position.x, _point.Position.y, _point.Position.z); } bool operator==(const PointEntry& _r) { - return key == MakeKey(_r.point.Position[0], _r.point.Position[1], _r.point.Position[2]); + return key == MakeKey(_r.point.Position.x, _r.point.Position.y, _r.point.Position.z); } static long MakeKey(float x, float y, float z) { @@ -60,22 +61,30 @@ struct PointEntry { } }; +// Mesh points type. +enum ENUM_MESH_TYPE { MESH_TYPE_CONNECTED_POINTS, MESH_TYPE_SEPARATE_POINTS }; + template class Mesh : public Dynamic { Ref vbuff; Ref ibuff; Face faces[]; + TSR tsr; + ENUM_MESH_TYPE type; public: /** * Constructor. */ - Mesh() {} + Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) { type = _type; } /** * Adds a single 3 or 4-vertex face. */ - void AddFace(Face& face) { Util::ArrayPush(faces, face, 16); } + void AddFace(Face& face) { + face.UpdateNormal(); + Util::ArrayPush(faces, face, 16); + } /** * Returns vertex and index buffers for this mesh. @@ -83,6 +92,7 @@ class Mesh : public Dynamic { * @todo Buffers should be invalidated if mesh has changed. */ bool GetBuffers(Device* _device, VertexBuffer*& _vbuff, IndexBuffer*& _ibuff) { + Print("Getting buffers. Mesh type = ", EnumToString(type)); if (vbuff.IsSet() && ibuff.IsSet()) { _vbuff = vbuff.Ptr(); _ibuff = ibuff.Ptr(); @@ -100,12 +110,12 @@ class Mesh : public Dynamic { // Adding first triangle. for (k = 0; k < 3; ++k) { - PointEntry point1(_face.points[k]); - _face_indices[k] = _points.IndexOf(point1); + PointEntry _point1(_face.points[k]); + _face_indices[k] = type == MESH_TYPE_SEPARATE_POINTS ? -1 : _points.IndexOf(_point1); if (_face_indices[k] == -1) { // Point not yet added. - _points.Push(point1); + _points.Push(_point1); _face_indices[k] = (int)_points.Size() - 1; } @@ -114,18 +124,36 @@ class Mesh : public Dynamic { // Adding second triangle if needed. if ((_face.flags & FACE_FLAGS_QUAD) == FACE_FLAGS_QUAD) { - PointEntry point2(_face.points[3]); - _face_indices[3] = _points.IndexOf(point2); - - if (_face_indices[3] == -1) { - // Point not yet added. - _points.Push(point2); - _face_indices[3] = (int)_points.Size() - 1; + if (type == MESH_TYPE_CONNECTED_POINTS) { + PointEntry _point3(_face.points[3]); + _face_indices[3] = _points.IndexOf(_point3); + + if (_face_indices[3] == -1) { + // Point not yet added. + _points.Push(_point3); + _face_indices[3] = (int)_points.Size() - 1; + } + + Util::ArrayPush(_indices, _face_indices[0]); + Util::ArrayPush(_indices, _face_indices[2]); + Util::ArrayPush(_indices, _face_indices[3]); + } else { + int _i1 = ArraySize(_indices) + 0; + int _i2 = ArraySize(_indices) + 1; + int _i3 = ArraySize(_indices) + 2; + + Util::ArrayPush(_indices, _i1); + Util::ArrayPush(_indices, _i2); + Util::ArrayPush(_indices, _i3); + + PointEntry _point0(_face.points[0]); + PointEntry _point2(_face.points[2]); + PointEntry _point3(_face.points[3]); + + _points.Push(_point0); + _points.Push(_point2); + _points.Push(_point3); } - - Util::ArrayPush(_indices, _face_indices[0]); - Util::ArrayPush(_indices, _face_indices[2]); - Util::ArrayPush(_indices, _face_indices[3]); } } @@ -139,10 +167,10 @@ class Mesh : public Dynamic { for (i = 0; i < ArraySize(_vertices); ++i) { _s_vertices += "["; - _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position[0]) + ", " + - DoubleToString(_vertices[i].Position[1]) + "," + DoubleToString(_vertices[i].Position[2]) + " | "; - _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color[0]) + ", " + DoubleToString(_vertices[i].Color[1]) + - "," + DoubleToString(_vertices[i].Color[2]) + "," + DoubleToString(_vertices[i].Color[3]); + _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position.x) + ", " + + DoubleToString(_vertices[i].Position.y) + "," + DoubleToString(_vertices[i].Position.z) + " | "; + _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color.x) + ", " + DoubleToString(_vertices[i].Color.y) + + "," + DoubleToString(_vertices[i].Color.z) + "," + DoubleToString(_vertices[i].Color.w); _s_vertices += "]"; if (i != ArraySize(_vertices) - 1) { _s_vertices += ", "; diff --git a/3D/Shader.h b/3D/Shader.h index 1500a1430..1b3b09938 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -38,6 +38,17 @@ class MTDXShader; enum ENUM_GFX_VAR_TYPE_FLOAT { GFX_VAR_TYPE_INT32, GFX_VAR_TYPE_FLOAT }; +// Note that shader buffers's size must be multiple of 4! +struct MVPBuffer { + DXMatrix world; + DXMatrix view; + DXMatrix projection; + DXVector3 lightdir; + + private: + char _unused[4]; +}; + // Vertex layout used for Vertex Shaders. struct ShaderVertexLayout { string name; diff --git a/3D/Shaders/chart3d.ps.hlsl b/3D/Shaders/chart3d.ps.hlsl new file mode 100644 index 000000000..e69de29bb diff --git a/3D/Shaders/chart3d.vs.hlsl b/3D/Shaders/chart3d.vs.hlsl new file mode 100644 index 000000000..e69de29bb diff --git a/3D/TSR.h b/3D/TSR.h new file mode 100644 index 000000000..09247b830 --- /dev/null +++ b/3D/TSR.h @@ -0,0 +1,61 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Translations, scale and rotation matrices. + */ + +#include "Math.h" + +struct TSR { + DXVector3 translation; + DXVector3 scale; + DXVector3 rotation; + + TSR() { + translation.x = translation.y = translation.z = 0.0f; + scale.x = scale.y = scale.z = 1.0f; + rotation.x = rotation.y = rotation.z = 0.0f; + } + + DXMatrix ToMatrix() const { + DXMatrix _mtx_translation = {}; + DXMatrix _mtx_scale = {}; + DXMatrix _mtx_rotation_1 = {}; + DXMatrix _mtx_rotation_2 = {}; + DXMatrix _mtx_result = {}; + + DXMatrixTranslation(_mtx_translation, translation.x, translation.y, translation.z); + DXMatrixScaling(_mtx_scale, scale.x, scale.y, scale.z); + DXMatrixRotationYawPitchRoll(_mtx_rotation_1, rotation.x, 0, rotation.z); + DXMatrixRotationYawPitchRoll(_mtx_rotation_2, 0, rotation.y, 0); + + DXMatrixIdentity(_mtx_result); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_1); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_2); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_scale); + + return _mtx_result; + } +}; \ No newline at end of file diff --git a/Util.h b/Util.h index e562d1955..06676caf0 100644 --- a/Util.h +++ b/Util.h @@ -43,4 +43,14 @@ class Util { _array[ArraySize(_array) - 1] = _value; return ArraySize(_array) - 1; } + + /** + * Resizes native array and reserves space for further items by some fixed step. + */ + template + static T ArrayPop(T& _array[]) { + T _result = _array[ArraySize(_array) - 1]; + ::ArrayResize(_array, ArraySize(_array) - 1); + return _result; + } }; \ No newline at end of file diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index e4ddb278c..6cdb51f59 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,11 +1,14 @@ -struct PSInput +struct INPUT { float4 position : SV_POSITION; + float4 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; float4 color : COLOR; }; -float4 main(PSInput input) : SV_TARGET +float4 main(INPUT input) : SV_TARGET { - return input.color; + float4 ambient = {0.0, 0.2, 0.4, 1.0}; + return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); } //+------------------------------------------------------------------+ diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index 6a92c8b1b..ab4715043 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -1,32 +1,38 @@ -cbuffer CBuffer +cbuffer MVP : register(b0) { matrix world; matrix view; - matrix proj; + matrix projection; + float3 lightdir; }; -struct VSInput +struct INPUT { float4 position : POSITION; + float3 normal : NORMAL; float4 color : COLOR; }; -struct PSInput +struct OUTPUT { float4 position : SV_POSITION; + float3 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; float4 color : COLOR; }; -PSInput main(VSInput input) +OUTPUT main(INPUT input) { - PSInput output; + OUTPUT output; input.position.w = 1.0f; - output.position = mul(world, input.position); - output.position = mul(view, output.position); - output.position = mul(proj, output.position); + matrix mvp = mul(mul(projection, view), world); + output.position = mul(mvp, input.position); + + output.normal = normalize(mul(world, input.normal)); + output.lightdir = lightdir; output.color = input.color; return output; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 6211ca9ac..c3b3d43a5 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -30,6 +30,8 @@ #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; +//#define Print if (false) Print + // Includes. #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" @@ -42,83 +44,79 @@ // int OnStart() { return OnInit(); } struct Vertex { - float Position[3]; - float Color[4]; + DXVector3 Position; + DXVector3 Normal; + DXVector Color; Vertex() { - Color[0] = 1.0f / 65535 * rand(); - Color[1] = 1.0f / 65535 * rand(); - Color[2] = 1.0f / 65535 * rand(); - Color[3] = 1.0f; + Color.x = 1.0f; + Color.y = 1.0f; + Color.z = 1.0f; + Color.w = 1.0f; } }; const ShaderVertexLayout VertexLayout[] = { {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, - {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 3}, -}; + {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, + {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; -struct PSCBuffer { - DXMatrix world; - DXMatrix view; - DXMatrix proj; -}; +struct PSCBuffer : MVPBuffer {}; /** * Implements Oninit(). */ int OnInit() { Ref gfx_ptr = new MTDXDevice(); - Device* gfx = gfx_ptr.Ptr(); - gfx.Start(new MT5Frontend()); + // Making a scope to ensure graphics device will be destructed as last. + { + Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); - Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Device* gfx = gfx_ptr.Ptr(); - Ref> _mesh = new Cube(0, 0, 0, 10, 20, 30); + gfx.Start(new MT5Frontend()); - unsigned int _rand_color = rand() * 1256; + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); + Ref _shader_p = gfx.PixelShader(ShaderSourcePS); - while (!IsStopped()) { - if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { - break; - } + unsigned int _rand_color = rand() * 1256; - gfx.Begin(_rand_color); + gfx.SetCameraOrtho3D(); + gfx.SetLightDirection(0, 0, -1.0f); - PSCBuffer psCBuffer; + while (!IsStopped()) { + if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { + break; + } - DXMatrixIdentity(psCBuffer.world); - DXMatrixIdentity(psCBuffer.view); - DXMatrixIdentity(psCBuffer.proj); - DXMatrixPerspectiveFovLH(psCBuffer.proj, (float)M_PI / 6, 1.5f, 0.1f, 1000.0f); - DXMatrixLookAtLH(psCBuffer.view, DXVector3(0, 0, -125), DXVector3(0, 0, 0), DXVector3(0, 1, 0)); + gfx.Begin(0x777255EE); - DXMatrix rotate_x; - static float x = 0; - x += 0.03f; - DXMatrixRotationX(rotate_x, x); + static float x = 0; + x += 0.04f; - DXMatrix rotate_y; - static float y = 0; - y += 0.01f; - DXMatrixRotationY(rotate_y, y); + TSR tsr; + tsr.rotation.x = x; - DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_x); - DXMatrixMultiply(psCBuffer.world, psCBuffer.world, rotate_y); + gfx.PushTransform(tsr); + gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.PopTransform(); - _shader_v.Ptr().SetCBuffer(psCBuffer); - gfx.SetShader(_shader_p.Ptr(), _shader_v.Ptr()); + tsr.translation.x = 50; + tsr.translation.y = -180; + tsr.rotation.z = 1.9f; - gfx.Render(_mesh.Ptr()); + gfx.PushTransform(tsr); + gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.PopTransform(); - gfx.End(); + gfx.End(); - // break; - } + // break; + } - gfx.Stop(); + gfx.Stop(); + } return (INIT_SUCCEEDED); } From efa3b10dd5ba2dab9e5f1325826b25e78b954041 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 7 May 2021 19:32:11 +0200 Subject: [PATCH 18/97] WIP. Battle with MetaEditor and Visualizer... --- 3D/Chart3D.h | 94 +++++++++++++++++-- 3D/Chart3DCandles.h | 52 ++++++++++ 3D/Chart3DType.h | 50 ++++++++++ 3D/Cube.h | 12 +++ 3D/Device.h | 10 +- 3D/Mesh.h | 38 +++++++- .../{chart3d.ps.hlsl => chart3d_ps.hlsl} | 0 .../{chart3d.vs.hlsl => chart3d_vs.hlsl} | 0 3D/Shaders/cube_ps.hlsl | 12 +++ 3D/Shaders/cube_vs.hlsl | 35 +++++++ 3D/Vertex.h | 29 ++++-- tests/3DTest.mq5 | 45 ++++----- 12 files changed, 328 insertions(+), 49 deletions(-) create mode 100644 3D/Chart3DCandles.h create mode 100644 3D/Chart3DType.h rename 3D/Shaders/{chart3d.ps.hlsl => chart3d_ps.hlsl} (100%) rename 3D/Shaders/{chart3d.vs.hlsl => chart3d_vs.hlsl} (100%) create mode 100644 3D/Shaders/cube_ps.hlsl create mode 100644 3D/Shaders/cube_vs.hlsl diff --git a/3D/Chart3D.h b/3D/Chart3D.h index bf093884e..4cb721ed7 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -25,28 +25,106 @@ * 3D Chart. */ +#include "../Bar.struct.h" #include "../Refs.mqh" +#include "../SerializerConverter.mqh" +#include "../SerializerJson.mqh" +#include "Chart3DCandles.h" +#include "Chart3DType.h" #include "Cube.h" #include "Device.h" // Resources. -#resource "Shaders/chart3d.ps.hlsl" as string Chart3DShaderSourcePS; -#resource "Shaders/chart3d.vs.hlsl" as string Chart3DShaderSourceVS; +#resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; +#resource "Shaders/chart3d_ps.hlsl" as string Chart3DShaderSourcePS; +typedef BarOHLC (*Chart3DPriceFetcher)(ENUM_TIMEFRAMES, int); + +// Type of the currently rendered 3d chart. +enum ENUM_CHART3D_TYPE { + CHART3D_TYPE_BARS, + CHART3D_TYPE_CANDLES, + CHART3D_TYPE_LINES, +}; + +/** + * 3D chart renderer. + */ class Chart3D : public Dynamic { - // Reference to graphics device. - WeakRef device; + // Camera offset. Z component indicates number of bars per screen's width. + DXVector3 offset; + + // Current chart type. + ENUM_CHART3D_TYPE type; + + // References to chart type renderers. + Ref renderers[3]; + + // OHLC prices fetcher callback. + Chart3DPriceFetcher price_fetcher; + + // Whether graphics were initialized. + bool initialized; + + // Shaders. + Ref shader_vs; + Ref shader_ps; public: /** * Constructor. */ - VertexBuffer(Device* _device) { device = _device; } + Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) { + price_fetcher = _price_fetcher; + type = _type; + offset.x = offset.y = 0.0f; + offset.z = 25.0f; + initialized = false; + } + + Shader* GetShaderVS() { return shader_vs.Ptr(); } + + Shader* GetShaderPS() { return shader_ps.Ptr(); } + + Chart3DType* GetRenderer(Device* _device) { + if (!initialized) { + // shader_vs = _device.VertexShader(Chart3DShaderSourceVS, Vertex::Layout); + // shader_ps = _device.PixelShader(Chart3DShaderSourcePS); + initialized = true; + } + + if (!renderers[type].IsSet()) { + switch (type) { + case CHART3D_TYPE_BARS: + // renderers[type] = new Chart3DBars(_device); + break; + case CHART3D_TYPE_CANDLES: + renderers[type] = new Chart3DCandles(&this, _device); + break; + case CHART3D_TYPE_LINES: + // renderers[type] = new Chart3DLines(_device); + break; + default: + Alert("Internal error: Wrong type for Chart3D in Chart3D::GetRenderer()!"); + DebugBreak(); + return NULL; + } + } + + return renderers[type].Ptr(); + } + + BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } /** - * Returns base graphics device. + * Renders chart. */ - Device* GetDevice() { return device.Ptr(); } + void Render(Device* _device) { + Chart3DType* _type_renderer = GetRenderer(_device); + + BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); + Print(SerializerConverter::FromObject(_ohlc).ToString()); - virtual void Select() = NULL; + _type_renderer.Render(_device); + } }; \ No newline at end of file diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h new file mode 100644 index 000000000..48e0ef336 --- /dev/null +++ b/3D/Chart3DCandles.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * 3D chart candles renderer. + */ + +#include "Chart3DType.h" +#include "Device.h" +#include "Vertex.h" + +class Chart; + +/** + * 3D chart candles renderer. + */ +class Chart3DCandles : public Chart3DType { + Ref> cube; + + public: + /** + * Constructor. + */ + Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { + cube = new Cube(100.0f, 100.0f, 100.0f); + } + + /** + * Renders chart. + */ + virtual void Render(Device* _device) { _device.Render(cube.Ptr()); } +}; \ No newline at end of file diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h new file mode 100644 index 000000000..6ff1ad808 --- /dev/null +++ b/3D/Chart3DType.h @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * 3D chart type renderer. + */ + +#include "../Refs.mqh" +#include "Device.h" + +class Chart3D; +class Device; + +/** + * 3D chart type renderer. + */ +class Chart3DType : public Dynamic { + public: + Device* device; + + /** + * Constructor. + */ + Chart3DType(Chart3D* _chart3d, Device* _device) : device(_device) {} + + /** + * Renders chart. + */ + virtual void Render(Device* _device) {} +}; \ No newline at end of file diff --git a/3D/Cube.h b/3D/Cube.h index e9ea4d095..efc3d7478 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -28,6 +28,10 @@ #include "Face.h" #include "Mesh.h" +// Resources. +#resource "Shaders/cube_ps.hlsl" as string ShaderCubeSourcePS; +#resource "Shaders/cube_vs.hlsl" as string ShaderCubeSourceVS; + /** * Cube mesh. */ @@ -64,4 +68,12 @@ class Cube : public Mesh { AddFace(f5); AddFace(f6); } + + /** + * Initializes graphics device-related things. + */ + virtual void Initialize(Device* _device) { + SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); + SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); + } }; \ No newline at end of file diff --git a/3D/Device.h b/3D/Device.h index 6d0777244..513b810dd 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -177,13 +177,9 @@ class Device : public Dynamic { VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); - if (_vs != NULL) { - SetShader(_vs); - } - if (_ps != NULL) { - SetShader(_ps); - } - // Setting MVP matrices. + + SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS()); + SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS()); Render(_vertices, _indices); } diff --git a/3D/Mesh.h b/3D/Mesh.h index d09d6ab1a..681a63851 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -68,15 +68,26 @@ template class Mesh : public Dynamic { Ref vbuff; Ref ibuff; + Ref shader_ps; + Ref shader_vs; Face faces[]; TSR tsr; ENUM_MESH_TYPE type; + bool initialized; public: /** * Constructor. */ - Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) { type = _type; } + Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) { + type = _type; + initialized = false; + } + + /** + * Initializes graphics device-related things. + */ + virtual void Initialize(Device* _device) {} /** * Adds a single 3 or 4-vertex face. @@ -86,12 +97,37 @@ class Mesh : public Dynamic { Util::ArrayPush(faces, face, 16); } + /** + * Returns vertex shader for mesh rendering. + */ + Shader* GetShaderVS() { return shader_vs.Ptr(); } + + /** + * Sets pixel shader for mesh rendering. + */ + void SetShaderVS(Shader* _shader_vs) { shader_vs = _shader_vs; } + + /** + * Returns pixel shader for mesh rendering. + */ + Shader* GetShaderPS() { return shader_ps.Ptr(); } + + /** + * Sets pixel shader for mesh rendering. + */ + void SetShaderPS(Shader* _shader_ps) { shader_ps = _shader_ps; } + /** * Returns vertex and index buffers for this mesh. * * @todo Buffers should be invalidated if mesh has changed. */ bool GetBuffers(Device* _device, VertexBuffer*& _vbuff, IndexBuffer*& _ibuff) { + if (!initialized) { + Initialize(_device); + initialized = true; + } + Print("Getting buffers. Mesh type = ", EnumToString(type)); if (vbuff.IsSet() && ibuff.IsSet()) { _vbuff = vbuff.Ptr(); diff --git a/3D/Shaders/chart3d.ps.hlsl b/3D/Shaders/chart3d_ps.hlsl similarity index 100% rename from 3D/Shaders/chart3d.ps.hlsl rename to 3D/Shaders/chart3d_ps.hlsl diff --git a/3D/Shaders/chart3d.vs.hlsl b/3D/Shaders/chart3d_vs.hlsl similarity index 100% rename from 3D/Shaders/chart3d.vs.hlsl rename to 3D/Shaders/chart3d_vs.hlsl diff --git a/3D/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl new file mode 100644 index 000000000..b6710ff2d --- /dev/null +++ b/3D/Shaders/cube_ps.hlsl @@ -0,0 +1,12 @@ +struct INPUT { + float4 position : SV_POSITION; + float4 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; + float4 color : COLOR; +}; + +float4 main(INPUT input) : SV_TARGET { + float4 ambient = {0.0, 0.2, 0.4, 1.0}; + return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); +} +//+------------------------------------------------------------------+ diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl new file mode 100644 index 000000000..a1ea75989 --- /dev/null +++ b/3D/Shaders/cube_vs.hlsl @@ -0,0 +1,35 @@ +cbuffer MVP : register(b0) { + matrix world; + matrix view; + matrix projection; + float3 lightdir; +}; + +struct INPUT { + float4 position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR; +}; + +struct OUTPUT { + float4 position : SV_POSITION; + float3 normal : TEXCOORD0; + float3 lightdir : TEXCOORD1; + float4 color : COLOR; +}; + +OUTPUT main(INPUT input) { + OUTPUT output; + + input.position.w = 1.0f; + + matrix mvp = mul(mul(projection, view), world); + + output.position = mul(mvp, input.position); + + output.normal = normalize(mul(world, input.normal)); + output.lightdir = lightdir; + output.color = input.color; + + return output; +} \ No newline at end of file diff --git a/3D/Vertex.h b/3D/Vertex.h index 6561fad32..83ccfe50f 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -1,11 +1,24 @@ #include "../Refs.mqh" +/** + * Generic vertex to be used by meshes. + */ struct Vertex { - struct Position { - float x, y, z; - } position; - - struct Color { - float r, g, b, a; - } color; -}; \ No newline at end of file + DXVector3 Position; + DXVector3 Normal; + DXVector Color; + + Vertex() { + Color.x = 1.0f; + Color.y = 1.0f; + Color.z = 1.0f; + Color.w = 1.0f; + } + + static const ShaderVertexLayout Layout[3]; +}; + +const ShaderVertexLayout Vertex::Layout[3] = { + {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, + {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, + {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index c3b3d43a5..a58290c6f 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -33,53 +33,46 @@ //#define Print if (false) Print // Includes. +#include "../3D/Chart3D.h" #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" #include "../3D/Devices/MTDX/MTDXIndexBuffer.h" #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../3D/Frontends/MT5Frontend.h" +#include "../Chart.mqh" +#include "../Serializer.mqh" #include "../Test.mqh" // int OnStart() { return OnInit(); } -struct Vertex { - DXVector3 Position; - DXVector3 Normal; - DXVector Color; +BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { return Chart::GetOHLC(_tf, _shift); } - Vertex() { - Color.x = 1.0f; - Color.y = 1.0f; - Color.z = 1.0f; - Color.w = 1.0f; - } -}; - -const ShaderVertexLayout VertexLayout[] = { - {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, - {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, - {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; +int OnInit() { return OnStart(); } struct PSCBuffer : MVPBuffer {}; /** - * Implements Oninit(). + * Implements OnStart(). */ -int OnInit() { +int OnStart() { Ref gfx_ptr = new MTDXDevice(); // Making a scope to ensure graphics device will be destructed as last. { - Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); - Device* gfx = gfx_ptr.Ptr(); gfx.Start(new MT5Frontend()); - Ref _shader_v = gfx.VertexShader(ShaderSourceVS, VertexLayout); + Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); Ref _shader_p = gfx.PixelShader(ShaderSourcePS); + Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); + _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); + _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); + + Ref _chart = new Chart3D(ChartPriceFeeder, CHART3D_TYPE_CANDLES); + unsigned int _rand_color = rand() * 1256; gfx.SetCameraOrtho3D(); @@ -99,7 +92,7 @@ int OnInit() { tsr.rotation.x = x; gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.Render(_mesh.Ptr()); gfx.PopTransform(); tsr.translation.x = 50; @@ -107,17 +100,19 @@ int OnInit() { tsr.rotation.z = 1.9f; gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr(), _shader_v.Ptr(), _shader_p.Ptr()); + gfx.Render(_mesh.Ptr()); gfx.PopTransform(); + _chart.Ptr().Render(gfx); + gfx.End(); // break; } - - gfx.Stop(); } + gfx_ptr.Ptr().Stop(); + return (INIT_SUCCEEDED); } From 2d42ee7752c01f00984fa120fafc20088edf2be7 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 7 May 2021 23:21:31 +0200 Subject: [PATCH 19/97] Serializer: Improves flag feature logic --- Serializer.mqh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Serializer.mqh b/Serializer.mqh index ed84d61f1..5c99a1df0 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -229,20 +229,20 @@ class Serializer { } // Is field dynamic? - if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_DYNAMIC) != SERIALIZER_FLAG_INCLUDE_DYNAMIC) { + if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_DYNAMIC) == SERIALIZER_FLAG_INCLUDE_DYNAMIC) { if ((field_flags & SERIALIZER_FIELD_FLAG_DYNAMIC) == SERIALIZER_FIELD_FLAG_DYNAMIC) { - return false; + return true; } } // Is field a feature? - if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_FEATURE) != SERIALIZER_FLAG_INCLUDE_FEATURE) { + if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_FEATURE) == SERIALIZER_FLAG_INCLUDE_FEATURE) { if ((field_flags & SERIALIZER_FIELD_FLAG_FEATURE) == SERIALIZER_FIELD_FLAG_FEATURE) { - return false; + return true; } } - return true; + return false; } /** From 44f265060893168aaea14a26739a344c42374c58 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 11 May 2021 13:38:10 +0200 Subject: [PATCH 20/97] Fixed serializers bugs regarding flags misuse, fields visibility and invalid value-to-int conversion. --- Convert.mqh | 34 +++++++++++++++++++++++++++++++++- Serializer.mqh | 22 ++++++++++++++++------ SerializerJson.mqh | 39 ++++++++++++++++++++++++++++++++++++++- tests/ConfigTest.mq5 | 9 ++++++++- tests/SerializerTest.mq5 | 2 +- 5 files changed, 96 insertions(+), 10 deletions(-) diff --git a/Convert.mqh b/Convert.mqh index 8676112cd..7ff9bbe9f 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -312,22 +312,54 @@ public: _out = _value != "" && _value != NULL && _value != "0" && _value != "false"; } + static void StringToType(string _value, char& _out) { + _out = (char)StringToInteger(_value); + } + + static void StringToType(string _value, unsigned char& _out) { + _out = (unsigned char)StringToInteger(_value); + } + static void StringToType(string _value, int& _out) { _out = (int)StringToInteger(_value); } + static void StringToType(string _value, unsigned int& _out) { + _out = (unsigned int)StringToInteger(_value); + } + static void StringToType(string _value, long& _out) { - _out = StringToInteger(_value); + _out = (long)StringToInteger(_value); + } + + static void StringToType(string _value, unsigned long& _out) { + _out = (unsigned long)StringToInteger(_value); } static void StringToType(string _value, short& _out) { _out = (short) StringToInteger(_value); } + static void StringToType(string _value, unsigned short& _out) { + _out = (unsigned short) StringToInteger(_value); + } + + static void StringToType(string _value, float& _out) { + _out = (float)StringToDouble(_value); + } + static void StringToType(string _value, double& _out) { _out = StringToDouble(_value); } + static void StringToType(string _value, color& _out) { + _out = StringToColor(_value); + } + + static void StringToType(string _value, datetime& _out) { + _out = StringToTime(_value); + } + static void StringToType(string _value, string& _out) { _out = _value; } diff --git a/Serializer.mqh b/Serializer.mqh index 5c99a1df0..5e1647eb8 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -25,6 +25,7 @@ #define SERIALIZER_MQH // Includes. +#include "Convert.mqh" #include "DictBase.mqh" #include "Log.mqh" #include "Serializer.define.h" @@ -60,6 +61,10 @@ class Serializer { _logger = new Log(); _root_node_ownership = true; fp_precision = SERIALIZER_DEFAULT_FP_PRECISION; + if (_flags == 0) { + // Preventing flags misuse. + _flags = SERIALIZER_FLAG_INCLUDE_ALL; + } } /** @@ -208,6 +213,13 @@ class Serializer { return true; } + if ((field_flags & SERIALIZER_FIELD_FLAG_HIDDEN) == SERIALIZER_FIELD_FLAG_HIDDEN) { + if ((serializer_flags & SERIALIZER_FLAG_SKIP_HIDDEN) != SERIALIZER_FLAG_SKIP_HIDDEN) { + // Field is hidden, but serializer has no SERIALIZER_FLAG_SKIP_HIDDEN flag set, so field will be serialized. + return true; + } + } + // Is field hidden? if ((serializer_flags & SERIALIZER_FLAG_SKIP_HIDDEN) == SERIALIZER_FLAG_SKIP_HIDDEN) { if ((field_flags & SERIALIZER_FIELD_FLAG_HIDDEN) == SERIALIZER_FIELD_FLAG_HIDDEN) { @@ -306,11 +318,9 @@ class Serializer { int num_items; if (_mode == Serialize) { - if ((_flags & SERIALIZER_FLAG_SKIP_HIDDEN) == SERIALIZER_FLAG_SKIP_HIDDEN) { - if ((flags & SERIALIZER_FIELD_FLAG_HIDDEN) == SERIALIZER_FIELD_FLAG_HIDDEN) { - // Skipping prematurely instead of creating object by new. - return; - } + if (!IsFieldVisible(_flags, flags)) { + // Skipping prematurely instead of creating object by new. + return; } } @@ -407,7 +417,7 @@ class Serializer { value = (V)child.GetValueParam()._integral._double; break; case SerializerNodeParamString: - value = (V)(int)child.GetValueParam()._string; + Convert::StringToType(child.GetValueParam()._string, value); break; } diff --git a/SerializerJson.mqh b/SerializerJson.mqh index be4dab091..72378504d 100644 --- a/SerializerJson.mqh +++ b/SerializerJson.mqh @@ -157,6 +157,11 @@ class SerializerJson { k = i + 1; do { ch2 = StringGetCharacter(data, k++); + if (GetLastError() == 5041) { + ResetLastError(); + ch2 = 0; + break; + } } while (ch2 == ' ' || ch2 == '\t' || ch2 == '\n' || ch2 == '\r'); if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') continue; @@ -169,7 +174,6 @@ class SerializerJson { } if (expectingKey) { key = SerializerNodeParam::FromString(extracted); - expectingKey = false; expectingSemicolon = true; } else if (expectingValue) { @@ -177,6 +181,11 @@ class SerializerJson { current.GetType() == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, key, SerializerNodeParam::FromString(extracted))); +#ifdef __debug__ + Print("SerializerJson: Value \"" + extracted + "\" for key " + + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + expectingValue = false; } else { return GracefulReturn("Unexpected '\"' symbol", i, root, key); @@ -195,6 +204,10 @@ class SerializerJson { return GracefulReturn("Cannot use object as a key", i, root, key); } +#ifdef __debug__ + Print("SerializerJson: Entering object for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + node = new SerializerNode(SerializerNodeObject, current, key); if (!root) root = node; @@ -212,9 +225,19 @@ class SerializerJson { return GracefulReturn("Unexpected end of object", i, root, key); } +#ifdef __debug__ + Print("SerializerJson: Leaving object for key " + (current != NULL && current.GetKeyParam() != NULL + ? ("\"" + current.GetKeyParam().ToString() + "\"") + : "")); +#endif + current = current.GetParent(); expectingValue = false; } else if (ch == '[') { +#ifdef __debug__ + Print("SerializerJson: Entering list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + if (expectingKey) { return GracefulReturn("Cannot use array as a key", i, root, key); } @@ -230,6 +253,10 @@ class SerializerJson { isOuterScope = false; key = NULL; } else if (ch == ']') { +#ifdef __debug__ + Print("SerializerJson: Leaving list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + if (expectingKey || expectingValue || current.GetType() != SerializerNodeArray) { return GracefulReturn("Unexpected end of array", i, root, key); } @@ -247,6 +274,11 @@ class SerializerJson { value = StringFind(extracted, ".") != -1 ? SerializerNodeParam::FromValue(StringToDouble(extracted)) : SerializerNodeParam::FromValue(StringToInteger(extracted)); +#ifdef __debug__ + Print("SerializerJson: Value " + value.AsString() + " for key " + + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + current.AddChild(new SerializerNode( current.GetType() == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, key, value)); @@ -262,6 +294,11 @@ class SerializerJson { value = SerializerNodeParam::FromValue(ch == 't' ? true : false); +#ifdef __debug__ + Print("SerializerJson: Value " + (value.ToBool() ? "true" : "false") + " for key " + + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + // Skipping value. i += ch == 't' ? 3 : 4; diff --git a/tests/ConfigTest.mq5 b/tests/ConfigTest.mq5 index 036a86698..88ab0510a 100644 --- a/tests/ConfigTest.mq5 +++ b/tests/ConfigTest.mq5 @@ -98,6 +98,11 @@ int OnInit() { // @todo // assertTrueOrFail(config.SaveToFile("config.ini", CONFIG_FORMAT_INI), "Cannot save config into the file!"); assertTrueOrFail(config.LoadFromFile("config.json"), "Cannot load config from the file!"); + + Print("There are ", config.Size(), " properites in config."); + Print("config[\"pair\"].type = \"", EnumToString(config["pair"].type), "\""); + Print("config[\"pair\"].string_value = \"", config["pair"].string_value, "\""); + assertTrueOrFail(config.LoadFromFile("config-minified.json"), "Cannot save config into the file!"); // @todo @@ -109,10 +114,12 @@ int OnInit() { configs.Push(config); Print("There are ", configs[0].Size(), " properites in configs[0]!"); + Print("configs[0][\"pair\"].type = \"", EnumToString(configs[0]["pair"].type), "\""); + Print("configs[0][\"pair\"].string_value = \"", configs[0]["pair"].string_value, "\""); SerializerConverter stub = SerializerConverter::MakeStubObject>(0, 1, configs[0].Size()); - SerializerConverter::FromObject(configs, 0).ToFile("config.csv", SERIALIZER_CSV_INCLUDE_TITLES, &stub); + SerializerConverter::FromObject(configs).ToFile("config.csv", SERIALIZER_CSV_INCLUDE_TITLES, &stub); SerializerConverter::FromObject(configs, 0).ToFile("config_2.json"); diff --git a/tests/SerializerTest.mq5 b/tests/SerializerTest.mq5 index 357d0dd92..72c250afa 100644 --- a/tests/SerializerTest.mq5 +++ b/tests/SerializerTest.mq5 @@ -313,7 +313,7 @@ int OnInit() { buff_params.Add(limit, 5); buff_params.Add(doubleVal, 6); - SerializerConverter stub5 = SerializerConverter::MakeStubObject>(0); + SerializerConverter stub5 = SerializerConverter::MakeStubObject>(); SerializerConverter::FromObject(buff_params) .ToFile("buffer_struct.csv", SERIALIZER_CSV_INCLUDE_TITLES_TREE | SERIALIZER_CSV_INCLUDE_KEY, &stub5); From 85516f64db3f98e5c700f6e19408f0d41edd48f5 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 12 May 2021 20:33:30 +0200 Subject: [PATCH 21/97] WIP. First try to render bars. --- 3D/Chart3D.h | 19 ++ 3D/Chart3DCandles.h | 27 ++- 3D/Chart3DType.h | 6 +- 3D/Cube.h | 3 +- 3D/Device.h | 36 +++- 3D/Devices/MTDX/MTDXDevice.h | 14 ++ 3D/Devices/MTDX/MTDXIndexBuffer.h | 4 + 3D/Devices/MTDX/MTDXShader.h | 28 ++- 3D/Devices/MTDX/MTDXVertexBuffer.h | 6 + 3D/Face.h | 2 - 3D/Frontends/MT5Frontend.h | 26 ++- 3D/Math.h | 278 +++++++++++++++-------------- 3D/Mesh.h | 24 ++- 3D/Shader.h | 12 +- 3D/Shaders/cube_ps.hlsl | 3 +- 3D/Shaders/cube_vs.hlsl | 12 +- 3D/TSR.h | 3 +- 3D/Vertex.h | 10 +- Refs.struct.h | 4 + tests/3D/Shaders/pixel.hlsl | 10 +- tests/3DTest.mq5 | 27 +-- 21 files changed, 355 insertions(+), 199 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 4cb721ed7..e8568a482 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -116,6 +116,22 @@ class Chart3D : public Dynamic { BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } + int GetBarsVisibleShiftStart() { return 20; } + + int GetBarsVisibleShiftEnd() { return 0; } + + int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; } + + float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.1f / 2.0f + 1.1f * _shift; } + + float GetPriceScale(float price) { + float _scale_y = 1.0f; + float _price_min = 1.194f; + float _price_max = 1.20f; + // Print(price); + return _scale_y / (_price_max - _price_min) * (price - _price_min); + } + /** * Renders chart. */ @@ -123,7 +139,10 @@ class Chart3D : public Dynamic { Chart3DType* _type_renderer = GetRenderer(_device); BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); + +#ifdef __debug__ Print(SerializerConverter::FromObject(_ohlc).ToString()); +#endif _type_renderer.Render(_device); } diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 48e0ef336..baf4b45f6 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -26,27 +26,46 @@ */ #include "Chart3DType.h" +#include "Cube.h" #include "Device.h" #include "Vertex.h" -class Chart; +class Chart3D; /** * 3D chart candles renderer. */ class Chart3DCandles : public Chart3DType { - Ref> cube; + Ref> cube1; + Ref> cube2; public: /** * Constructor. */ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { - cube = new Cube(100.0f, 100.0f, 100.0f); + cube1 = new Cube(1.0f, 1.0f, 1.0f); + cube2 = new Cube(0.15f, 0.15f, 0.15f); } /** * Renders chart. */ - virtual void Render(Device* _device) { _device.Render(cube.Ptr()); } + virtual void Render(Device* _device) { + TSR _tsr; + + for (int _shift = chart3d.GetBarsVisibleShiftStart(); _shift != chart3d.GetBarsVisibleShiftEnd(); --_shift) { + BarOHLC _ohlc = chart3d.GetPrice(PERIOD_CURRENT, _shift); + + cube1.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); + cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.open); + cube1.Ptr().GetMaterial().SetColor(0xFF0000); + _device.Render(cube1.Ptr()); + + cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); + cube2.Ptr().GetTSR().scale.y = 10.0f; + cube2.Ptr().GetMaterial().SetColor(0xFF0000); + _device.Render(cube2.Ptr()); + } + } }; \ No newline at end of file diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h index 6ff1ad808..d96de2463 100644 --- a/3D/Chart3DType.h +++ b/3D/Chart3DType.h @@ -35,13 +35,15 @@ class Device; * 3D chart type renderer. */ class Chart3DType : public Dynamic { - public: + protected: + Chart3D* chart3d; Device* device; + public: /** * Constructor. */ - Chart3DType(Chart3D* _chart3d, Device* _device) : device(_device) {} + Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {} /** * Renders chart. diff --git a/3D/Cube.h b/3D/Cube.h index efc3d7478..5d0c69d45 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -38,7 +38,8 @@ template class Cube : public Mesh { public: - Cube(float size_x, float size_y, float size_z, float x = 0.0f, float y = 0.0f, float z = 0.0f) { + Cube(float size_x, float size_y, float size_z, float x = 0.0f, float y = 0.0f, float z = 0.0f) + : Mesh(MESH_TYPE_SEPARATE_POINTS) { float half_x = size_x / 2; float half_y = size_y / 2; float half_z = size_z / 2; diff --git a/3D/Device.h b/3D/Device.h index 513b810dd..5fd811132 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -29,6 +29,7 @@ #include "../Util.h" #include "Frontend.h" #include "IndexBuffer.h" +#include "Material.h" #include "Math.h" #include "Mesh.h" #include "Shader.h" @@ -48,6 +49,7 @@ class Device : public Dynamic { DXMatrix mtx_view; DXMatrix mtx_projection; DXVector3 lightdir; + Material material; public: /** @@ -65,8 +67,8 @@ class Device : public Dynamic { } void PushTransform(const TSR& tsr) { - mtx_world = tsr.ToMatrix(); Util::ArrayPush(mtx_stack, mtx_world); + DXMatrixMultiply(mtx_world, tsr.ToMatrix(), mtx_world); } void PopTransform() { mtx_world = Util::ArrayPop(mtx_stack); } @@ -115,6 +117,16 @@ class Device : public Dynamic { return &this; } + /** + * Returns current material. + */ + Material GetMaterial() { return material; } + + /** + * Assigns material for later rendering. + */ + void SetMaterial(Material& _material) { material = _material; } + /** * Returns graphics device context as integer. */ @@ -139,8 +151,10 @@ class Device : public Dynamic { VertexBuffer* _buff = VertexBuffer(); // Unfortunately we can't make this method virtual. if (dynamic_cast(_buff) != NULL) { - // MT5's DirectX. +// MT5's DirectX. +#ifdef __debug__ Print("Filling vertex buffer via MTDXVertexBuffer"); +#endif ((MTDXVertexBuffer*)_buff).Fill(data); } else { Alert("Unsupported vertex buffer device target"); @@ -173,15 +187,22 @@ class Device : public Dynamic { */ template void Render(Mesh* _mesh, Shader* _vs = NULL, Shader* _ps = NULL) { +#ifdef __debug__ Print("Rendering mesh"); +#endif VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); + PushTransform(_mesh.GetTSR()); + + SetMaterial(_mesh.GetMaterial()); SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS()); SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS()); Render(_vertices, _indices); + + PopTransform(); } /** @@ -207,7 +228,16 @@ class Device : public Dynamic { */ int Height() { return frontend.Ptr().Height(); } - void SetCameraOrtho3D() { DXMatrixOrthoRH(mtx_view, Width(), Height(), -10000, 10000); } + void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { + DXMatrixOrthoLH(mtx_view, 1.0f, 1.0f / Width() * Height(), -10000, 10000); + mtx_view.m[3][3] = _pos_z; + DXMatrix _translate; + DXMatrix _scale; + DXMatrixTranslation(_translate, _pos_x, _pos_y, 0.0f); + DXMatrixTranslation(_scale, 1.0f / _pos_z, 1.0f / _pos_z, 0.0f); + // DXMatrixMultiply(mtx_view, _translate, mtx_view); + // DXMatrixMultiply(mtx_view, mtx_view, _scale); + } DXMatrix GetWorldMatrix() { return mtx_world; } diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 96eddc266..6200f1b36 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -33,10 +33,14 @@ class MTDXDevice : public Device { * Initializes graphics device. */ bool Init(Frontend* _frontend) { +#ifdef __debug__ Print("MTDXDevice: DXContextCreate: width = ", _frontend.Width(), ", height = ", _frontend.Height()); +#endif context = DXContextCreate(_frontend.Width(), _frontend.Height()); +#ifdef __debug__ Print("LastError: ", GetLastError()); Print("MTDXDevice: context = ", context); +#endif _frontend.Init(); return true; } @@ -78,10 +82,14 @@ class MTDXDevice : public Device { _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); +#ifdef __debug__ Print("DXContextClearColors: LastError: ", GetLastError()); +#endif } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); +#ifdef __debug__ Print("DXContextClearDepth: LastError: ", GetLastError()); +#endif } } @@ -131,13 +139,19 @@ class MTDXDevice : public Device { _vertices.Select(); if (_indices == NULL) { if (!DXDraw(context)) { +#ifdef __debug__ Print("Can't draw!"); +#endif } +#ifdef __debug__ Print("DXDraw: LastError: ", GetLastError()); +#endif } else { _indices.Select(); DXDrawIndexed(context); +#ifdef __debug__ Print("DXDrawIndexed: LastError: ", GetLastError()); +#endif } } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index ae6d6ff3c..60b33124f 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -58,8 +58,12 @@ class MTDXIndexBuffer : public IndexBuffer { * Activates index buffer for rendering. */ virtual void Select() { +#ifdef __debug__ Print("Selecting indices ", handle); +#endif DXBufferSet(GetDevice().Context(), handle); +#ifdef __debug__ Print("Select: LastError: ", GetLastError()); +#endif } }; \ No newline at end of file diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index eacbfc484..6a5b951c4 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -63,13 +63,17 @@ class MTDXShader : public Shader { handle = DXShaderCreate(GetDevice().Context(), _type == SHADER_TYPE_VS ? DX_SHADER_VERTEX : DX_SHADER_PIXEL, _source_code, _entry_point, error_text); +#ifdef __debug__ Print("DXShaderCreate: LastError: ", GetLastError(), ", ErrorText: ", error_text); +#endif cbuffer_handle = 0; // Creating MVP buffer. cbuffer_mvp_handle = DXInputCreate(GetDevice().Context(), sizeof(MVPBuffer)); +#ifdef __debug__ Print("DXInputCreate (mvp): LastError: ", GetLastError()); +#endif return true; } @@ -83,7 +87,9 @@ class MTDXShader : public Shader { DXVertexLayout _target_layout[]; ArrayResize(_target_layout, ArraySize(_layout)); +#ifdef __debug__ Print("ArrayResize: LastError: ", GetLastError()); +#endif int i; @@ -93,16 +99,20 @@ class MTDXShader : public Shader { _target_layout[i].format = ParseFormat(_layout[i]); } +#ifdef __debug__ for (i = 0; i < ArraySize(_target_layout); ++i) { Print(_target_layout[i].semantic_name, ", ", _target_layout[i].semantic_index, ", ", EnumToString(_target_layout[i].format)); } Print("before DXShaderSetLayout: LastError: ", GetLastError()); +#endif DXShaderSetLayout(handle, _target_layout); +#ifdef __debug__ Print("DXShaderSetLayout: LastError: ", GetLastError()); +#endif ResetLastError(); } @@ -137,28 +147,36 @@ class MTDXShader : public Shader { void SetCBuffer(const X& data) { if (cbuffer_handle == 0) { cbuffer_handle = DXInputCreate(GetDevice().Context(), sizeof(X)); +#ifdef __debug__ Print("DXInputCreate: LastError: ", GetLastError()); +#endif int _input_handles[1]; _input_handles[0] = cbuffer_handle; DXShaderInputsSet(handle, _input_handles); +#ifdef __debug__ Print("DXShaderInputsSet: LastError: ", GetLastError()); +#endif } DXInputSet(cbuffer_handle, data); +#ifdef __debug__ Print("DXInputSet: LastError: ", GetLastError()); +#endif } /** * Selectes shader to be used by graphics device for rendering. */ virtual void Select() { - // Setting MVP transform. - mvp_buffer.world = GetDevice().GetWorldMatrix(); - mvp_buffer.view = GetDevice().GetViewMatrix(); - mvp_buffer.projection = GetDevice().GetProjectionMatrix(); + // Setting MVP transform and material information. + + DXMatrixTranspose(mvp_buffer.world, GetDevice().GetWorldMatrix()); + DXMatrixTranspose(mvp_buffer.view, GetDevice().GetViewMatrix()); + DXMatrixTranspose(mvp_buffer.projection, GetDevice().GetProjectionMatrix()); mvp_buffer.lightdir = GetDevice().GetLightDirection(); + mvp_buffer.mat_color = GetDevice().GetMaterial().Color; if (cbuffer_handle == 0) { int _input_handles[1]; @@ -171,7 +189,9 @@ class MTDXShader : public Shader { DXShaderInputsSet(handle, _input_handles); } +#ifdef __debug__ Print("DXShaderInputsSet: LastError: ", GetLastError()); +#endif DXInputSet(cbuffer_mvp_handle, mvp_buffer); DXShaderSet(GetDevice().Context(), handle); diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index c3cf7fdda..915d60979 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -44,14 +44,20 @@ class MTDXVertexBuffer : public VertexBuffer { template bool Fill(X& _data[]) { handle = DXBufferCreate(GetDevice().Context(), DX_BUFFER_VERTEX, _data); +#ifdef __debug__ Print("Created vb ", handle); Print("Fill: LastError: ", GetLastError()); +#endif return true; } virtual void Select() { +#ifdef __debug__ Print("Selecting vb ", handle); +#endif DXBufferSet(GetDevice().Context(), handle); +#ifdef __debug__ Print("Select: LastError: ", GetLastError()); +#endif } }; \ No newline at end of file diff --git a/3D/Face.h b/3D/Face.h index 7f7ad38af..76b87e26b 100644 --- a/3D/Face.h +++ b/3D/Face.h @@ -89,8 +89,6 @@ struct Face { DXVec3Cross(_normal, _v1, _v2); DXVec3Normalize(_normal, _normal); - // Print("cross = ", _normal.x, ", ", _normal.y, ", ", _normal.z); - for (int i = 0; i < 4; ++i) { points[i].Normal = _normal; } diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 357b4266a..6c88f1347 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -52,19 +52,23 @@ class MT5Frontend : public Frontend { ChartSetInteger(0, CHART_SHOW, false); ChartRedraw(); - Print("LastError: ", GetLastError()); +#ifdef __debug__ + Print("MT5 Frontend: LastError: ", GetLastError()); +#endif objname = "MT5_Frontend_" + IntegerToString(ChartID()); resname = "::MT5_Frontend" + IntegerToString(ChartID()); ObjectCreate(0, objname, OBJ_BITMAP_LABEL, 0, 0, 0); ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 0); ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 0); - Print("LastError: ", GetLastError()); - - Print("LastError: ", GetLastError()); +#ifdef __debug__ + Print("MT5 Frontend: ObjectCreate/Set: LastError: ", GetLastError()); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); +#endif ObjectSetString(ChartID(), objname, OBJPROP_BMPFILE, resname); +#ifdef __debug__ Print("LastError: ", GetLastError()); +#endif return true; } @@ -88,9 +92,13 @@ class MT5Frontend : public Frontend { } ArrayResize(image, Width() * Height()); +#ifdef __debug__ Print("resname = ", resname, ", image_size = ", ArraySize(image), ", width = ", Width(), ", height = ", Height()); +#endif ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); +#ifdef __debug__ Print("ResourceCreate: LastError: ", GetLastError()); +#endif last_width = Width(); last_height = Height(); @@ -102,27 +110,37 @@ class MT5Frontend : public Frontend { * Executed before render starts. */ virtual void RenderBegin(int context) { +#ifdef __debug__ Print("MT5Frontend: RenderBegin()"); Print("Image resize: width = ", Width(), ", height = ", Height()); +#endif if (Resize()) { DXContextSetSize(context, Width(), Height()); } +#ifdef __debug__ Print("DXContextSetSize: LastError: ", GetLastError()); +#endif } /** * Executed after render ends. */ virtual void RenderEnd(int context) { +#ifdef __debug__ Print("MT5Frontend: RenderEnd()"); Print("ResourceCreate: width = ", Width(), ", height = ", Height()); Print("MT5Frontend: DXContextGetColors()"); +#endif DXContextGetColors(context, image); +#ifdef __debug__ Print("DXContextGetColors: LastError: ", GetLastError()); +#endif ResourceCreate(resname, image, Width(), Height(), 0, 0, Width(), COLOR_FORMAT_ARGB_NORMALIZE); +#ifdef __debug__ Print("ResourceCreate: LastError: ", GetLastError()); +#endif ChartRedraw(); Sleep(5); } diff --git a/3D/Math.h b/3D/Math.h index f4ca30204..ae74f4092 100644 --- a/3D/Math.h +++ b/3D/Math.h @@ -72,6 +72,12 @@ struct DXColor { b = v.z; a = 1.0; } + DXColor(unsigned int _color) { + a = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); + r = 1.0f / 255.0f * ((_color & 0x00FF0000) >> 16); + g = 1.0f / 255.0f * ((_color & 0x0000FF00) >> 8); + b = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); + } }; //+------------------------------------------------------------------+ //| DXPlane | @@ -352,7 +358,7 @@ Bintensity,float &rout[],float &gout[],float &bout[]); int DXSHEvalHemisphereL order,const DXVector3 &dir,float radius,float Rintensity,float Gintensity,float Bintensity,float &rout[],float &gout[],float &bout[]); void DXSHMultiply2(float &out[],const float &a[],const float &b[]); void DXSHMultiply3(float &out[],const float &a[],const float &b[]); void DXSHMultiply4(float &out[],const float &a[],const float &b[]); void -DXSHRotate(float &out[],int order,const DXMatrix &matrix,const float &in[]); void DXSHRotateZ(float &out[],int +DXSHRotate(float &out[],int order,const DXMatrix &_matrix,const float &in[]); void DXSHRotateZ(float &out[],int order,float angle,const float &in[]); void DXSHScale(float &out[],int order,const float &a[],const float scale); //--- scalar functions @@ -627,8 +633,8 @@ void DXVec2Subtract(DXVector2 &pout, const DXVector2 &pv1, const DXVector2 &pv2) pout.y = pv1.y - pv2.y; } //+------------------------------------------------------------------+ -//| Transforms a 2D vector by a given matrix. | -//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//| Transforms a 2D vector by a given _matrix. | +//| This function transforms the vector pv(x,y,0,1) by the _matrix pm.| //+------------------------------------------------------------------+ void DXVec2Transform(DXVector4 &pout, const DXVector2 &pv, const DXMatrix &pm) { DXVector4 out; @@ -639,9 +645,9 @@ void DXVec2Transform(DXVector4 &pout, const DXVector2 &pv, const DXMatrix &pm) { pout = out; } //+------------------------------------------------------------------+ -//| Transforms a 2D vector by a given matrix, | +//| Transforms a 2D vector by a given _matrix, | //| projecting the result back into w = 1. | -//| This function transforms the vector pv(x,y,0,1) by the matrix pm.| +//| This function transforms the vector pv(x,y,0,1) by the _matrix pm.| //+------------------------------------------------------------------+ void DXVec2TransformCoord(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { float norm = pm.m[0][3] * pv.x + pm.m[1][3] * pv.y + pm.m[3][3]; @@ -654,7 +660,7 @@ void DXVec2TransformCoord(DXVector2 &pout, const DXVector2 &pv, const DXMatrix & } } //+------------------------------------------------------------------+ -//| Transforms the 2D vector normal by the given matrix. | +//| Transforms the 2D vector normal by the given _matrix. | //+------------------------------------------------------------------+ void DXVec2TransformNormal(DXVector2 &pout, const DXVector2 &pv, const DXMatrix &pm) { pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y; @@ -804,7 +810,7 @@ void DXVec3Subtract(DXVector3 &pout, const DXVector3 &pv1, const DXVector3 &pv2) pout.z = pv1.z - pv2.z; } //+------------------------------------------------------------------+ -//| Transforms vector (x,y,z,1) by a given matrix. | +//| Transforms vector (x,y,z,1) by a given _matrix. | //+------------------------------------------------------------------+ void DXVec3Transform(DXVector4 &pout, const DXVector3 &pv, const DXMatrix &pm) { DXVector4 out; @@ -816,7 +822,7 @@ void DXVec3Transform(DXVector4 &pout, const DXVector3 &pv, const DXMatrix &pm) { pout = out; } //+------------------------------------------------------------------+ -//| Transforms a 3D vector by a given matrix, | +//| Transforms a 3D vector by a given _matrix, | //| projecting the result back into w = 1. | //+------------------------------------------------------------------+ void DXVec3TransformCoord(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { @@ -833,7 +839,7 @@ void DXVec3TransformCoord(DXVector3 &pout, const DXVector3 &pv, const DXMatrix & } } //+------------------------------------------------------------------+ -//| Transforms the 3D vector normal by the given matrix. | +//| Transforms the 3D vector normal by the given _matrix. | //+------------------------------------------------------------------+ void DXVec3TransformNormal(DXVector3 &pout, const DXVector3 &pv, const DXMatrix &pm) { pout.x = pm.m[0][0] * pv.x + pm.m[1][0] * pv.y + pm.m[2][0] * pv.z; @@ -853,7 +859,7 @@ void DXVec3Unproject(DXVector3 &out, const DXVector3 &v, const DViewport &viewpo DXMatrixMultiply(m, m, view); //--- projection DXMatrixMultiply(m, m, projection); - //--- calculate inverse matrix + //--- calculate inverse _matrix float det = 0.0f; DXMatrixInverse(m, det, m); out = v; @@ -1009,7 +1015,7 @@ void DXVec4Subtract(DXVector4 &pout, const DXVector4 &pv1, const DXVector4 &pv2) pout.w = pv1.w - pv2.w; } //+------------------------------------------------------------------+ -//| Transforms a 4D vector by a given matrix. | +//| Transforms a 4D vector by a given _matrix. | //+------------------------------------------------------------------+ void DXVec4Transform(DXVector4 &pout, const DXVector4 &pv, const DXMatrix &pm) { DXVector4 temp; @@ -1154,7 +1160,7 @@ void DXQuaternionRotationAxis(DXQuaternion &out, const DXVector3 &v, float angle out.w = (float)cos(angle / 2.0f); } //+------------------------------------------------------------------+ -//| Builds a quaternion from a rotation matrix. | +//| Builds a quaternion from a rotation _matrix. | //+------------------------------------------------------------------+ void DXQuaternionRotationMatrix(DXQuaternion &out, const DXMatrix &m) { float s; @@ -1324,7 +1330,7 @@ void DXQuaternionToAxisAngle(const DXQuaternion &pq, DXVector3 &paxis, float &pa pangle = 2.0f * (float)acos(pq.w); } //+------------------------------------------------------------------+ -//| DXMatrixIdentity creates an identity matrix | +//| DXMatrixIdentity creates an identity _matrix | //+------------------------------------------------------------------+ void DXMatrixIdentity(DXMatrix &out) { for (int j = 0; j < 4; j++) @@ -1336,7 +1342,7 @@ void DXMatrixIdentity(DXMatrix &out) { } } //+------------------------------------------------------------------+ -//| Determines if a matrix is an identity matrix. | +//| Determines if a _matrix is an identity _matrix. | //+------------------------------------------------------------------+ bool DXMatrixIsIdentity(DXMatrix &pm) { for (int j = 0; j < 4; j++) @@ -1350,18 +1356,18 @@ bool DXMatrixIsIdentity(DXMatrix &pm) { return (true); } //+------------------------------------------------------------------+ -//| Builds a 3D affine transformation matrix. | +//| Builds a 3D affine transformation _matrix. | //+------------------------------------------------------------------+ -//| This function calculates the affine transformation matrix | -//| with the following formula, with matrix concatenation | +//| This function calculates the affine transformation _matrix | +//| with the following formula, with _matrix concatenation | //| evaluated in left-to-right order: | //| Mout = Ms * (Mrc)-1 * Mr * Mrc * Mt | //| where: | -//| Mout = output matrix (pOut) | -//| Ms = scaling matrix (Scaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (pRotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Ms = scaling _matrix (Scaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (pRotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixAffineTransformation(DXMatrix &out, float scaling, const DXVector3 &rotationcenter, const DXQuaternion &rotation, const DXVector3 &translation) { @@ -1396,18 +1402,18 @@ void DXMatrixAffineTransformation(DXMatrix &out, float scaling, const DXVector3 out.m[3][2] += translation.z; } //+------------------------------------------------------------------+ -//| Builds a 2D affine transformation matrix in the xy plane. | +//| Builds a 2D affine transformation _matrix in the xy plane. | //+------------------------------------------------------------------+ -//| This function calculates the affine transformation matrix | -//| with the following formula, with matrix concatenation evaluated | +//| This function calculates the affine transformation _matrix | +//| with the following formula, with _matrix concatenation evaluated | //| in left-to-right order: | //| Mout = Ms * (Mrc)^(-1) * Mr * Mrc * Mt | //| where: | -//| Mout = output matrix (pOut) | -//| Ms = scaling matrix (Scaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (Rotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Ms = scaling _matrix (Scaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (Rotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector2 &rotationcenter, float rotation, const DXVector2 &translation) { @@ -1432,7 +1438,7 @@ void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector #define D3DERR_INVALIDCALL -2005530516 //#define S_OK 0; //+------------------------------------------------------------------+ -//| Breaks down a general 3D transformation matrix into its scalar, | +//| Breaks down a general 3D transformation _matrix into its scalar, | //| rotational, and translational components. | //+------------------------------------------------------------------+ int DXMatrixDecompose(DXVector3 &poutscale, DXQuaternion &poutrotation, DXVector3 &pouttranslation, @@ -1473,7 +1479,7 @@ int DXMatrixDecompose(DXVector3 &poutscale, DXQuaternion &poutrotation, DXVector return (0); } //+------------------------------------------------------------------+ -//| Returns the determinant of a matrix. | +//| Returns the determinant of a _matrix. | //+------------------------------------------------------------------+ float DXMatrixDeterminant(const DXMatrix &pm) { float t[3], v[4]; @@ -1492,7 +1498,7 @@ float DXMatrixDeterminant(const DXMatrix &pm) { return (pm.m[0][0] * v[0] + pm.m[0][1] * v[1] + pm.m[0][2] * v[2] + pm.m[0][3] * v[3]); } //+------------------------------------------------------------------+ -//| Calculates the inverse of a matrix. | +//| Calculates the inverse of a _matrix. | //+------------------------------------------------------------------+ void DXMatrixInverse(DXMatrix &pout, float &pdeterminant, const DXMatrix &pm) { float t[3], v[16]; @@ -1562,9 +1568,9 @@ void DXMatrixInverse(DXMatrix &pout, float &pdeterminant, const DXMatrix &pm) { for (int j = 0; j < 4; j++) pout.m[i][j] = v[4 * i + j] * det; } //+------------------------------------------------------------------+ -//| Builds a left-handed,look-at matrix. | +//| Builds a left-handed,look-at _matrix. | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| | //| zaxis = normal(At - Eye) | //| xaxis = normal(cross(Up,zaxis)) | @@ -1602,10 +1608,10 @@ void DXMatrixLookAtLH(DXMatrix &out, const DXVector3 &eye, const DXVector3 &at, out.m[3][3] = 1.0f; } //+------------------------------------------------------------------+ -//| Builds a right-handed, look-at matrix. | +//| Builds a right-handed, look-at _matrix. | //+------------------------------------------------------------------+ //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| | //| zaxis = normal(Eye - At) | //| xaxis = normal(cross(Up,zaxis)) | @@ -1667,7 +1673,7 @@ void DXMatrixMultiplyTranspose(DXMatrix &pout, const DXMatrix &pm1, const DXMatr pout = temp; } //+------------------------------------------------------------------+ -//| Builds a left-handed orthographic projection matrix. | +//| Builds a left-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ void DXMatrixOrthoLH(DXMatrix &pout, float w, float h, float zn, float zf) { DXMatrixIdentity(pout); @@ -1678,7 +1684,7 @@ void DXMatrixOrthoLH(DXMatrix &pout, float w, float h, float zn, float zf) { pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a customized,left-handed orthographic projection matrix. | +//| Builds a customized,left-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ void DXMatrixOrthoOffCenterLH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { DXMatrixIdentity(pout); @@ -1691,7 +1697,7 @@ void DXMatrixOrthoOffCenterLH(DXMatrix &pout, float l, float r, float b, float t pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a customized,right-handed orthographic projection matrix. | +//| Builds a customized,right-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ void DXMatrixOrthoOffCenterRH(DXMatrix &pout, float l, float r, float b, float t, float zn, float zf) { DXMatrixIdentity(pout); @@ -1704,14 +1710,14 @@ void DXMatrixOrthoOffCenterRH(DXMatrix &pout, float l, float r, float b, float t pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a right-handed orthographic projection matrix. | +//| Builds a right-handed orthographic projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixOrthoRH function | //| are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix: | +//| the returned _matrix: | //| 2/w 0 0 0 | //| 0 2/h 0 0 | //| 0 0 1/(zn-zf) 0 | @@ -1725,10 +1731,10 @@ void DXMatrixOrthoRH(DXMatrix &pout, float w, float h, float zn, float zf) { pout.m[3][2] = zn / (zn - zf); } //+------------------------------------------------------------------+ -//| Builds a left-handed perspective projection matrix | +//| Builds a left-handed perspective projection _matrix | //| based on a field of view. | //+------------------------------------------------------------------+ -//| This function computes the returned matrix as shown: | +//| This function computes the returned _matrix as shown: | //| xScale 0 0 0 | //| 0 yScale 0 0 | //| 0 0 zf/(zf-zn) 1 | @@ -1748,10 +1754,10 @@ void DXMatrixPerspectiveFovLH(DXMatrix &pout, float fovy, float aspect, float zn pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a right-handed perspective projection matrix | +//| Builds a right-handed perspective projection _matrix | //| based on a field of view. | //+------------------------------------------------------------------+ -//| This function computes the returned matrix as shown. | +//| This function computes the returned _matrix as shown. | //| xScale 0 0 0 | //| 0 yScale 0 0 | //| 0 0 zf/(zn-zf) -1 | @@ -1771,10 +1777,10 @@ void DXMatrixPerspectiveFovRH(DXMatrix &pout, float fovy, float aspect, float zn pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a left-handed perspective projection matrix | +//| Builds a left-handed perspective projection _matrix | //+------------------------------------------------------------------+ //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/w 0 0 0 | //| 0 2*zn/h 0 0 | //| 0 0 zf/(zf-zn) 1 | @@ -1790,14 +1796,14 @@ void DXMatrixPerspectiveLH(DXMatrix &pout, float w, float h, float zn, float zf) pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a customized, left-handed perspective projection matrix. | +//| Builds a customized, left-handed perspective projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixPerspectiveOffCenterLH | //| function are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/(r-l) 0 0 0 | //| 0 2*zn/(t-b) 0 0 | //| (l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1 | @@ -1816,14 +1822,14 @@ void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout, float l, float r, float b, f pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a customized, right-handed perspective projection matrix. | +//| Builds a customized, right-handed perspective projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixPerspectiveOffCenterRH | //| function are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/(r-l) 0 0 0 | //| 0 2*zn/(t-b) 0 0 | //| (l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1 | @@ -1842,14 +1848,14 @@ void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout, float l, float r, float b, f pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a right-handed perspective projection matrix. | +//| Builds a right-handed perspective projection _matrix. | //+------------------------------------------------------------------+ //| All the parameters of the DXMatrixPerspectiveRH function | //| are distances in camera space. The parameters describe | //| the dimensions of the view volume. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| 2*zn/w 0 0 0 | //| 0 2*zn/h 0 0 | //| 0 0 zf/(zn-zf) -1 | @@ -1866,12 +1872,12 @@ void DXMatrixPerspectiveRH(DXMatrix &pout, float w, float h, float zn, float zf) pout.m[3][3] = 0.0f; } //+------------------------------------------------------------------+ -//| Builds a matrix that reflects the coordinate system about a plane| +//| Builds a _matrix that reflects the coordinate system about a plane| //| This function normalizes the plane equation before it creates | -//| the reflected matrix. | +//| the reflected _matrix. | //| | //| This function uses the following formula to compute | -//| the returned matrix. | +//| the returned _matrix. | //| P = normalize(Plane); | //| -2 * P.a * P.a + 1 -2 * P.b * P.a -2 * P.c * P.a 0 | //| -2 * P.a * P.b -2 * P.b * P.b + 1 -2 * P.c * P.b 0 | @@ -1897,7 +1903,7 @@ void DXMatrixReflect(DXMatrix &pout, const DXPlane &pplane) { pout.m[3][2] = -2.0f * Nplane.d * Nplane.c; } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around an arbitrary axis. | +//| Builds a _matrix that rotates around an arbitrary axis. | //+------------------------------------------------------------------+ void DXMatrixRotationAxis(DXMatrix &out, const DXVector3 &v, float angle) { DXVector3 nv; @@ -1925,7 +1931,7 @@ void DXMatrixRotationAxis(DXMatrix &out, const DXVector3 &v, float angle) { out.m[3][3] = 1.0f; } //+------------------------------------------------------------------+ -//| Builds a rotation matrix from a quaternion. | +//| Builds a rotation _matrix from a quaternion. | //+------------------------------------------------------------------+ void DXMatrixRotationQuaternion(DXMatrix &pout, const DXQuaternion &pq) { DXMatrixIdentity(pout); @@ -1941,7 +1947,7 @@ void DXMatrixRotationQuaternion(DXMatrix &pout, const DXQuaternion &pq) { pout.m[2][2] = 1.0f - 2.0f * (pq.x * pq.x + pq.y * pq.y); } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the x-axis. | +//| Builds a _matrix that rotates around the x-axis. | //+------------------------------------------------------------------+ void DXMatrixRotationX(DXMatrix &pout, float angle) { DXMatrixIdentity(pout); @@ -1952,7 +1958,7 @@ void DXMatrixRotationX(DXMatrix &pout, float angle) { pout.m[2][1] = -(float)sin(angle); } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the y-axis. | +//| Builds a _matrix that rotates around the y-axis. | //+------------------------------------------------------------------+ void DXMatrixRotationY(DXMatrix &pout, float angle) { DXMatrixIdentity(pout); @@ -1963,7 +1969,7 @@ void DXMatrixRotationY(DXMatrix &pout, float angle) { pout.m[2][0] = (float)sin(angle); } //+------------------------------------------------------------------+ -//| Builds a matrix with a specified yaw, pitch, and roll. | +//| Builds a _matrix with a specified yaw, pitch, and roll. | //+------------------------------------------------------------------+ //| The order of transformations is roll first, then pitch, then yaw.| //| Relative to the object's local coordinate axis, this is | @@ -1996,7 +2002,7 @@ void DXMatrixRotationYawPitchRoll(DXMatrix &out, float yaw, float pitch, float r out.m[3][3] = 1.0f; } //+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the z-axis. | +//| Builds a _matrix that rotates around the z-axis. | //+------------------------------------------------------------------+ void DXMatrixRotationZ(DXMatrix &pout, float angle) { DXMatrixIdentity(pout); @@ -2007,7 +2013,7 @@ void DXMatrixRotationZ(DXMatrix &pout, float angle) { pout.m[1][0] = -(float)sin(angle); } //+------------------------------------------------------------------+ -//| Builds a matrix that scales along the x-axis, | +//| Builds a _matrix that scales along the x-axis, | //| the y-axis,and the z-axis. | //+------------------------------------------------------------------+ void DXMatrixScaling(DXMatrix &pout, float sx, float sy, float sz) { @@ -2017,12 +2023,12 @@ void DXMatrixScaling(DXMatrix &pout, float sx, float sy, float sz) { pout.m[2][2] = sz; } //+------------------------------------------------------------------+ -//| Builds a matrix that flattens geometry into a plane. | +//| Builds a _matrix that flattens geometry into a plane. | //+------------------------------------------------------------------+ //| The DXMatrixShadow function flattens geometry into a plane, as | //| if casting a shadow from a light. | //| This function uses the following formula to compute the returned | -//| matrix. | +//| _matrix. | //| | //| P = normalize(Plane); | //| L = Light; | @@ -2060,22 +2066,22 @@ void DXMatrixShadow(DXMatrix &pout, const DXVector4 &plight, const DXPlane &ppla pout.m[3][3] = dot - Nplane.d * plight.w; } //+------------------------------------------------------------------+ -//| Builds a transformation matrix. | +//| Builds a transformation _matrix. | //+------------------------------------------------------------------+ -//| This function calculates the transformation matrix with the | -//| following formula, with matrix concatenation evaluated | +//| This function calculates the transformation _matrix with the | +//| following formula, with _matrix concatenation evaluated | //| in left-to-right order: | //| | //| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | //| | //| where: | -//| Mout = output matrix (pOut) | -//| Msc = scaling center matrix (pScalingCenter) | -//| Msr = scaling rotation matrix (pScalingRotation) | -//| Ms = scaling matrix (pScaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (pRotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Msc = scaling center _matrix (pScalingCenter) | +//| Msr = scaling rotation _matrix (pScalingRotation) | +//| Ms = scaling _matrix (pScaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (pRotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixTransformation(DXMatrix &pout, const DXVector3 &pscalingcenter, const DXQuaternion &pscalingrotation, const DXVector3 &pscaling, const DXVector3 &protationcenter, const DXQuaternion &protation, @@ -2119,23 +2125,23 @@ void DXMatrixTransformation(DXMatrix &pout, const DXVector3 &pscalingcenter, con DXMatrixMultiply(pout, m1, m7); } //+------------------------------------------------------------------+ -//| Builds a 2D transformation matrix that represents | +//| Builds a 2D transformation _matrix that represents | //| transformations in the xy plane. | //+------------------------------------------------------------------+ -//| This function calculates the transformation matrix with the | -//| following formula, with matrix concatenation evaluated | +//| This function calculates the transformation _matrix with the | +//| following formula, with _matrix concatenation evaluated | //| in left-to-right order: | //| | //| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | //| | //| where: | -//| Mout = output matrix (pOut) | -//| Msc = scaling center matrix (pScalingCenter) | -//| Msr = scaling rotation matrix (pScalingRotation) | -//| Ms = scaling matrix (pScaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (Rotation) | -//| Mt = translation matrix (pTranslation) | +//| Mout = output _matrix (pOut) | +//| Msc = scaling center _matrix (pScalingCenter) | +//| Msr = scaling rotation _matrix (pScalingRotation) | +//| Ms = scaling _matrix (pScaling) | +//| Mrc = center of rotation _matrix (pRotationCenter) | +//| Mr = rotation _matrix (Rotation) | +//| Mt = translation _matrix (pTranslation) | //+------------------------------------------------------------------+ void DXMatrixTransformation2D(DXMatrix &pout, const DXVector2 &pscalingcenter, float scalingrotation, const DXVector2 &pscaling, const DXVector2 &protationcenter, float rotation, @@ -2171,7 +2177,7 @@ void DXMatrixTransformation2D(DXMatrix &pout, const DXVector2 &pscalingcenter, f DXMatrixTransformation(pout, sca_center, sca_rot, sca, rot_center, rot, trans); } //+------------------------------------------------------------------+ -//| Builds a matrix using the specified offsets. | +//| Builds a _matrix using the specified offsets. | //+------------------------------------------------------------------+ void DXMatrixTranslation(DXMatrix &pout, float x, float y, float z) { DXMatrixIdentity(pout); @@ -2181,7 +2187,7 @@ void DXMatrixTranslation(DXMatrix &pout, float x, float y, float z) { pout.m[3][2] = z; } //+------------------------------------------------------------------+ -//| Returns the matrix transpose of a matrix. | +//| Returns the _matrix transpose of a _matrix. | //+------------------------------------------------------------------+ void DXMatrixTranspose(DXMatrix &pout, const DXMatrix &pm) { const DXMatrix m = pm; @@ -2287,8 +2293,8 @@ void DXPlaneScale(DXPlane &pout, const DXPlane &p, float s) { pout.d = p.d * s; }; //+------------------------------------------------------------------+ -//| Transforms a plane by a matrix. | -//| The input matrix is the inverse transpose of the actual | +//| Transforms a plane by a _matrix. | +//| The input _matrix is the inverse transpose of the actual | //| transformation. | //+------------------------------------------------------------------+ void DXPlaneTransform(DXPlane &pout, const DXPlane &pplane, const DXMatrix &pm) { @@ -3068,7 +3074,7 @@ void rotate_X(float &out[], uint order, float a, float &in[]) { out[35] = 0.9057110548f * in[31] - 0.4192627370f * in[33] + 0.0624999329f * in[35]; } //+------------------------------------------------------------------+ -//| Rotates the spherical harmonic (SH) vector by the given matrix. | +//| Rotates the spherical harmonic (SH) vector by the given _matrix. | //+------------------------------------------------------------------+ //| Each coefficient of the basis function Y(l,m) | //| is stored at memory location l^2 + m + l, where: | @@ -3076,57 +3082,57 @@ void rotate_X(float &out[], uint order, float a, float &in[]) { //| m is the basis function index for the given l value | //| and ranges from -l to l, inclusive. | //+------------------------------------------------------------------+ -void DXSHRotate(float &out[], int order, const DXMatrix &matrix, const float &in[]) { +void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &in[]) { float alpha, beta, gamma, sinb, temp[36], temp1[36]; out[0] = in[0]; if ((order > DXSH_MAXORDER) || (order < DXSH_MINORDER)) return; if (order <= 3) { - out[1] = matrix.m[1][1] * in[1] - matrix.m[2][1] * in[2] + matrix.m[0][1] * in[3]; - out[2] = -matrix.m[1][2] * in[1] + matrix.m[2][2] * in[2] - matrix.m[0][2] * in[3]; - out[3] = matrix.m[1][0] * in[1] - matrix.m[2][0] * in[2] + matrix.m[0][0] * in[3]; + out[1] = _matrix.m[1][1] * in[1] - _matrix.m[2][1] * in[2] + _matrix.m[0][1] * in[3]; + out[2] = -_matrix.m[1][2] * in[1] + _matrix.m[2][2] * in[2] - _matrix.m[0][2] * in[3]; + out[3] = _matrix.m[1][0] * in[1] - _matrix.m[2][0] * in[2] + _matrix.m[0][0] * in[3]; if (order == 3) { float coeff[12] = {}; - coeff[0] = matrix.m[1][0] * matrix.m[0][0]; - coeff[1] = matrix.m[1][1] * matrix.m[0][1]; - coeff[2] = matrix.m[1][1] * matrix.m[2][1]; - coeff[3] = matrix.m[1][0] * matrix.m[2][0]; - coeff[4] = matrix.m[2][0] * matrix.m[2][0]; - coeff[5] = matrix.m[2][1] * matrix.m[2][1]; - coeff[6] = matrix.m[0][0] * matrix.m[2][0]; - coeff[7] = matrix.m[0][1] * matrix.m[2][1]; - coeff[8] = matrix.m[0][1] * matrix.m[0][1]; - coeff[9] = matrix.m[1][0] * matrix.m[1][0]; - coeff[10] = matrix.m[1][1] * matrix.m[1][1]; - coeff[11] = matrix.m[0][0] * matrix.m[0][0]; - - out[4] = (matrix.m[1][1] * matrix.m[0][0] + matrix.m[0][1] * matrix.m[1][0]) * in[4]; - out[4] -= (matrix.m[1][0] * matrix.m[2][1] + matrix.m[1][1] * matrix.m[2][0]) * in[5]; - out[4] += 1.7320508076f * matrix.m[2][0] * matrix.m[2][1] * in[6]; - out[4] -= (matrix.m[0][1] * matrix.m[2][0] + matrix.m[0][0] * matrix.m[2][1]) * in[7]; - out[4] += (matrix.m[0][0] * matrix.m[0][1] - matrix.m[1][0] * matrix.m[1][1]) * in[8]; - - out[5] = (matrix.m[1][1] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][1]) * in[5]; - out[5] -= (matrix.m[1][1] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][1]) * in[4]; - out[5] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][1] * in[6]; - out[5] += (matrix.m[0][2] * matrix.m[2][1] + matrix.m[0][1] * matrix.m[2][2]) * in[7]; - out[5] -= (matrix.m[0][1] * matrix.m[0][2] - matrix.m[1][1] * matrix.m[1][2]) * in[8]; - - out[6] = (matrix.m[2][2] * matrix.m[2][2] - 0.5f * (coeff[4] + coeff[5])) * in[6]; - out[6] -= (0.5773502692f * (coeff[0] + coeff[1]) - 1.1547005384f * matrix.m[1][2] * matrix.m[0][2]) * in[4]; - out[6] += (0.5773502692f * (coeff[2] + coeff[3]) - 1.1547005384f * matrix.m[1][2] * matrix.m[2][2]) * in[5]; - out[6] += (0.5773502692f * (coeff[6] + coeff[7]) - 1.1547005384f * matrix.m[0][2] * matrix.m[2][2]) * in[7]; + coeff[0] = _matrix.m[1][0] * _matrix.m[0][0]; + coeff[1] = _matrix.m[1][1] * _matrix.m[0][1]; + coeff[2] = _matrix.m[1][1] * _matrix.m[2][1]; + coeff[3] = _matrix.m[1][0] * _matrix.m[2][0]; + coeff[4] = _matrix.m[2][0] * _matrix.m[2][0]; + coeff[5] = _matrix.m[2][1] * _matrix.m[2][1]; + coeff[6] = _matrix.m[0][0] * _matrix.m[2][0]; + coeff[7] = _matrix.m[0][1] * _matrix.m[2][1]; + coeff[8] = _matrix.m[0][1] * _matrix.m[0][1]; + coeff[9] = _matrix.m[1][0] * _matrix.m[1][0]; + coeff[10] = _matrix.m[1][1] * _matrix.m[1][1]; + coeff[11] = _matrix.m[0][0] * _matrix.m[0][0]; + + out[4] = (_matrix.m[1][1] * _matrix.m[0][0] + _matrix.m[0][1] * _matrix.m[1][0]) * in[4]; + out[4] -= (_matrix.m[1][0] * _matrix.m[2][1] + _matrix.m[1][1] * _matrix.m[2][0]) * in[5]; + out[4] += 1.7320508076f * _matrix.m[2][0] * _matrix.m[2][1] * in[6]; + out[4] -= (_matrix.m[0][1] * _matrix.m[2][0] + _matrix.m[0][0] * _matrix.m[2][1]) * in[7]; + out[4] += (_matrix.m[0][0] * _matrix.m[0][1] - _matrix.m[1][0] * _matrix.m[1][1]) * in[8]; + + out[5] = (_matrix.m[1][1] * _matrix.m[2][2] + _matrix.m[1][2] * _matrix.m[2][1]) * in[5]; + out[5] -= (_matrix.m[1][1] * _matrix.m[0][2] + _matrix.m[1][2] * _matrix.m[0][1]) * in[4]; + out[5] -= 1.7320508076f * _matrix.m[2][2] * _matrix.m[2][1] * in[6]; + out[5] += (_matrix.m[0][2] * _matrix.m[2][1] + _matrix.m[0][1] * _matrix.m[2][2]) * in[7]; + out[5] -= (_matrix.m[0][1] * _matrix.m[0][2] - _matrix.m[1][1] * _matrix.m[1][2]) * in[8]; + + out[6] = (_matrix.m[2][2] * _matrix.m[2][2] - 0.5f * (coeff[4] + coeff[5])) * in[6]; + out[6] -= (0.5773502692f * (coeff[0] + coeff[1]) - 1.1547005384f * _matrix.m[1][2] * _matrix.m[0][2]) * in[4]; + out[6] += (0.5773502692f * (coeff[2] + coeff[3]) - 1.1547005384f * _matrix.m[1][2] * _matrix.m[2][2]) * in[5]; + out[6] += (0.5773502692f * (coeff[6] + coeff[7]) - 1.1547005384f * _matrix.m[0][2] * _matrix.m[2][2]) * in[7]; out[6] += (0.2886751347f * (coeff[9] - coeff[8] + coeff[10] - coeff[11]) - - 0.5773502692f * (matrix.m[1][2] * matrix.m[1][2] - matrix.m[0][2] * matrix.m[0][2])) * + 0.5773502692f * (_matrix.m[1][2] * _matrix.m[1][2] - _matrix.m[0][2] * _matrix.m[0][2])) * in[8]; - out[7] = (matrix.m[0][0] * matrix.m[2][2] + matrix.m[0][2] * matrix.m[2][0]) * in[7]; - out[7] -= (matrix.m[1][0] * matrix.m[0][2] + matrix.m[1][2] * matrix.m[0][0]) * in[4]; - out[7] += (matrix.m[1][0] * matrix.m[2][2] + matrix.m[1][2] * matrix.m[2][0]) * in[5]; - out[7] -= 1.7320508076f * matrix.m[2][2] * matrix.m[2][0] * in[6]; - out[7] -= (matrix.m[0][0] * matrix.m[0][2] - matrix.m[1][0] * matrix.m[1][2]) * in[8]; + out[7] = (_matrix.m[0][0] * _matrix.m[2][2] + _matrix.m[0][2] * _matrix.m[2][0]) * in[7]; + out[7] -= (_matrix.m[1][0] * _matrix.m[0][2] + _matrix.m[1][2] * _matrix.m[0][0]) * in[4]; + out[7] += (_matrix.m[1][0] * _matrix.m[2][2] + _matrix.m[1][2] * _matrix.m[2][0]) * in[5]; + out[7] -= 1.7320508076f * _matrix.m[2][2] * _matrix.m[2][0] * in[6]; + out[7] -= (_matrix.m[0][0] * _matrix.m[0][2] - _matrix.m[1][0] * _matrix.m[1][2]) * in[8]; out[8] = 0.5f * (coeff[11] - coeff[8] - coeff[9] + coeff[10]) * in[8]; out[8] += (coeff[0] - coeff[1]) * in[4]; @@ -3137,13 +3143,13 @@ void DXSHRotate(float &out[], int order, const DXMatrix &matrix, const float &in return; } - if ((float)fabs(matrix.m[2][2]) != 1.0f) { - sinb = (float)sqrt(1.0f - matrix.m[2][2] * matrix.m[2][2]); - alpha = (float)atan2(matrix.m[2][1] / sinb, matrix.m[2][0] / sinb); - beta = (float)atan2(sinb, matrix.m[2][2]); - gamma = (float)atan2(matrix.m[1][2] / sinb, -matrix.m[0][2] / sinb); + if ((float)fabs(_matrix.m[2][2]) != 1.0f) { + sinb = (float)sqrt(1.0f - _matrix.m[2][2] * _matrix.m[2][2]); + alpha = (float)atan2(_matrix.m[2][1] / sinb, _matrix.m[2][0] / sinb); + beta = (float)atan2(sinb, _matrix.m[2][2]); + gamma = (float)atan2(_matrix.m[1][2] / sinb, -_matrix.m[0][2] / sinb); } else { - alpha = (float)atan2(matrix.m[0][1], matrix.m[0][0]); + alpha = (float)atan2(_matrix.m[0][1], _matrix.m[0][0]); beta = 0.0f; gamma = 0.0f; } diff --git a/3D/Mesh.h b/3D/Mesh.h index 681a63851..94b8e9f0a 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -30,6 +30,7 @@ #include "../Util.h" #include "Face.h" #include "IndexBuffer.h" +#include "Material.h" #include "Math.h" #include "TSR.h" #include "VertexBuffer.h" @@ -74,6 +75,7 @@ class Mesh : public Dynamic { TSR tsr; ENUM_MESH_TYPE type; bool initialized; + Material material; public: /** @@ -89,6 +91,10 @@ class Mesh : public Dynamic { */ virtual void Initialize(Device* _device) {} + TSR* GetTSR() { return &tsr; } + + void SetTSR(const TSR& _tsr) { tsr = _tsr; } + /** * Adds a single 3 or 4-vertex face. */ @@ -97,6 +103,16 @@ class Mesh : public Dynamic { Util::ArrayPush(faces, face, 16); } + /** + * Returns material assigned to mesh. + */ + Material* GetMaterial() { return &material; } + + /** + * Assigns material to mesh. + */ + void SetMaterial(Material& _material) { material = _material; } + /** * Returns vertex shader for mesh rendering. */ @@ -128,7 +144,9 @@ class Mesh : public Dynamic { initialized = true; } +#ifdef __debug__ Print("Getting buffers. Mesh type = ", EnumToString(type)); +#endif if (vbuff.IsSet() && ibuff.IsSet()) { _vbuff = vbuff.Ptr(); _ibuff = ibuff.Ptr(); @@ -205,8 +223,8 @@ class Mesh : public Dynamic { _s_vertices += "["; _s_vertices += " Pos = " + DoubleToString(_vertices[i].Position.x) + ", " + DoubleToString(_vertices[i].Position.y) + "," + DoubleToString(_vertices[i].Position.z) + " | "; - _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color.x) + ", " + DoubleToString(_vertices[i].Color.y) + - "," + DoubleToString(_vertices[i].Color.z) + "," + DoubleToString(_vertices[i].Color.w); + _s_vertices += " Clr = " + DoubleToString(_vertices[i].Color.r) + ", " + DoubleToString(_vertices[i].Color.g) + + "," + DoubleToString(_vertices[i].Color.b) + "," + DoubleToString(_vertices[i].Color.a); _s_vertices += "]"; if (i != ArraySize(_vertices) - 1) { _s_vertices += ", "; @@ -226,8 +244,10 @@ class Mesh : public Dynamic { _s_indices += "]"; +#ifdef __debug__ Print("Vertices: ", _s_vertices); Print("Indices: ", _s_indices); +#endif vbuff = _vbuff = _device.VertexBuffer(_vertices); ibuff = _ibuff = _device.IndexBuffer(_indices); diff --git a/3D/Shader.h b/3D/Shader.h index 1b3b09938..c586092de 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -46,7 +46,13 @@ struct MVPBuffer { DXVector3 lightdir; private: - char _unused[4]; + float _unused1; + + public: + DXColor mat_color; + + private: + // char _unused2[1]; }; // Vertex layout used for Vertex Shaders. @@ -85,8 +91,10 @@ class Shader : public Dynamic { void SetCBuffer(const X& data) { // Unfortunately we can't make this method virtual. if (dynamic_cast(&this) != NULL) { - // MT5's DirectX. +// MT5's DirectX. +#ifdef __debug__ Print("Setting CBuffer data for MT5"); +#endif ((MTDXShader*)&this).SetCBuffer(data); } else { Alert("Unsupported cbuffer device target"); diff --git a/3D/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl index b6710ff2d..beaeada19 100644 --- a/3D/Shaders/cube_ps.hlsl +++ b/3D/Shaders/cube_ps.hlsl @@ -7,6 +7,5 @@ struct INPUT { float4 main(INPUT input) : SV_TARGET { float4 ambient = {0.0, 0.2, 0.4, 1.0}; - return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); + return ambient + input.color * saturate(dot(input.lightdir, input.normal)); } -//+------------------------------------------------------------------+ diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl index a1ea75989..a4928a1d7 100644 --- a/3D/Shaders/cube_vs.hlsl +++ b/3D/Shaders/cube_vs.hlsl @@ -3,6 +3,7 @@ cbuffer MVP : register(b0) { matrix view; matrix projection; float3 lightdir; + float4 mat_color; }; struct INPUT { @@ -21,15 +22,12 @@ struct OUTPUT { OUTPUT main(INPUT input) { OUTPUT output; - input.position.w = 1.0f; + matrix mvp = mul(mul(world, view), projection); + output.position = mul(input.position, mvp); - matrix mvp = mul(mul(projection, view), world); - - output.position = mul(mvp, input.position); - - output.normal = normalize(mul(world, input.normal)); + output.normal = normalize(mul(input.normal, world)); output.lightdir = lightdir; - output.color = input.color; + output.color = input.color * mat_color; return output; } \ No newline at end of file diff --git a/3D/TSR.h b/3D/TSR.h index 09247b830..d56f8ecc3 100644 --- a/3D/TSR.h +++ b/3D/TSR.h @@ -27,7 +27,8 @@ #include "Math.h" -struct TSR { +class TSR { + public: DXVector3 translation; DXVector3 scale; DXVector3 rotation; diff --git a/3D/Vertex.h b/3D/Vertex.h index 83ccfe50f..8466fa312 100644 --- a/3D/Vertex.h +++ b/3D/Vertex.h @@ -6,13 +6,13 @@ struct Vertex { DXVector3 Position; DXVector3 Normal; - DXVector Color; + DXColor Color; Vertex() { - Color.x = 1.0f; - Color.y = 1.0f; - Color.z = 1.0f; - Color.w = 1.0f; + Color.r = 1.0f; + Color.g = 1.0f; + Color.b = 1.0f; + Color.a = 1.0f; } static const ShaderVertexLayout Layout[3]; diff --git a/Refs.struct.h b/Refs.struct.h index 784cd4fd2..232dc1732 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -107,6 +107,10 @@ struct Ref { ptr_object.ptr_ref_counter = NULL; ptr_object = NULL; +#ifdef __debug__ + Print("Refs: Deleting object ", ptr_to_delete); +#endif + delete ptr_to_delete; } diff --git a/tests/3D/Shaders/pixel.hlsl b/tests/3D/Shaders/pixel.hlsl index 6cdb51f59..9d94f4069 100644 --- a/tests/3D/Shaders/pixel.hlsl +++ b/tests/3D/Shaders/pixel.hlsl @@ -1,14 +1,12 @@ -struct INPUT -{ +struct INPUT { float4 position : SV_POSITION; float4 normal : TEXCOORD0; float3 lightdir : TEXCOORD1; float4 color : COLOR; }; -float4 main(INPUT input) : SV_TARGET -{ - float4 ambient = {0.0, 0.2, 0.4, 1.0}; - return ambient + float4(1.0, 0.0, 0.0, 0.0) * saturate(dot(input.lightdir, input.normal)); +float4 main(INPUT input) : SV_TARGET { + float4 ambient = {0.0, 0.2, 0.4, 1.0}; + return ambient + input.color * saturate(dot(input.lightdir, input.normal)); } //+------------------------------------------------------------------+ diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index a58290c6f..5ed5a0f9b 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -26,6 +26,8 @@ #ifdef __MQL5__ +//#define __debug__ + // Resources. #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; @@ -50,8 +52,6 @@ BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { return Chart::GetOHL int OnInit() { return OnStart(); } -struct PSCBuffer : MVPBuffer {}; - /** * Implements OnStart(). */ @@ -67,7 +67,7 @@ int OnStart() { Ref _shader_v = gfx.VertexShader(ShaderSourceVS, Vertex::Layout); Ref _shader_p = gfx.PixelShader(ShaderSourcePS); - Ref> _mesh = new Cube(250.0f, 250.0f, 250.0f); + Ref> _mesh = new Cube(1.0f, 1.0f, 1.0f); _mesh.Ptr().SetShaderVS(_shader_v.Ptr()); _mesh.Ptr().SetShaderPS(_shader_p.Ptr()); @@ -75,8 +75,8 @@ int OnStart() { unsigned int _rand_color = rand() * 1256; - gfx.SetCameraOrtho3D(); - gfx.SetLightDirection(0, 0, -1.0f); + gfx.SetCameraOrtho3D(0.0f, 0.0f, 20.0f); + gfx.SetLightDirection(0.0f, 0.0f, -1.0f); while (!IsStopped()) { if ((TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) & 0x8000) != 0) { @@ -86,24 +86,15 @@ int OnStart() { gfx.Begin(0x777255EE); static float x = 0; - x += 0.04f; + x += 0.0f; TSR tsr; - tsr.rotation.x = x; + tsr.rotation.y = sin(x) / 3; + tsr.rotation.x = sin(x / 4) / 3; gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr()); - gfx.PopTransform(); - - tsr.translation.x = 50; - tsr.translation.y = -180; - tsr.rotation.z = 1.9f; - - gfx.PushTransform(tsr); - gfx.Render(_mesh.Ptr()); - gfx.PopTransform(); - _chart.Ptr().Render(gfx); + gfx.PopTransform(); gfx.End(); From 1c0f4687f1e13d35fa883c346754803f0c54ff64 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Thu, 13 May 2021 22:31:18 +0200 Subject: [PATCH 22/97] WIP. Added candles chart rendering and price cache. --- 3D/Chart3D.h | 36 +++++++++++++++++++++++++++++------- 3D/Chart3DCandles.h | 33 ++++++++++++++++++++++++++++----- 3D/Device.h | 13 ++++--------- 3D/Frontends/MT5Frontend.h | 2 +- 3D/Material.h | 18 ++++++++++++++++++ 3D/Shaders/cube_ps.hlsl | 10 ++++++++-- 3D/Shaders/cube_vs.hlsl | 2 +- 3D/TSR.h | 2 +- tests/3DTest.mq5 | 37 +++++++++++++++++++++++++++++-------- 9 files changed, 119 insertions(+), 34 deletions(-) create mode 100644 3D/Material.h diff --git a/3D/Chart3D.h b/3D/Chart3D.h index e8568a482..fdafdf0ac 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -116,20 +116,42 @@ class Chart3D : public Dynamic { BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } - int GetBarsVisibleShiftStart() { return 20; } + int GetBarsVisibleShiftStart() { return 80; } int GetBarsVisibleShiftEnd() { return 0; } + float GetMinBarsPrice() { + float _min = 100.0f; + for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { + BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); + if (_ohlc.GetMinOC() < _min) { + _min = _ohlc.GetMinOC(); + } + } + return _min; + } + + float GetMaxBarsPrice() { + float _max = -100.0f; + for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { + BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); + if (_ohlc.GetMaxOC() > _max) { + _max = _ohlc.GetMaxOC(); + } + } + return _max; + } + int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; } - float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.1f / 2.0f + 1.1f * _shift; } + float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.25f / 2.0f + 1.25f * _shift; } float GetPriceScale(float price) { - float _scale_y = 1.0f; - float _price_min = 1.194f; - float _price_max = 1.20f; - // Print(price); - return _scale_y / (_price_max - _price_min) * (price - _price_min); + float _scale_y = 20.0f; + float _price_min = GetMinBarsPrice(); + float _price_max = GetMaxBarsPrice(); + float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y; + return _result; } /** diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index baf4b45f6..c230003c1 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -38,6 +38,7 @@ class Chart3D; class Chart3DCandles : public Chart3DType { Ref> cube1; Ref> cube2; + Ref> cube3; public: /** @@ -45,7 +46,8 @@ class Chart3DCandles : public Chart3DType { */ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { cube1 = new Cube(1.0f, 1.0f, 1.0f); - cube2 = new Cube(0.15f, 0.15f, 0.15f); + cube2 = new Cube(0.15f, 1.0f, 0.15f); + cube3 = new Cube(1.0f, 0.15f, 0.15f); } /** @@ -57,15 +59,36 @@ class Chart3DCandles : public Chart3DType { for (int _shift = chart3d.GetBarsVisibleShiftStart(); _shift != chart3d.GetBarsVisibleShiftEnd(); --_shift) { BarOHLC _ohlc = chart3d.GetPrice(PERIOD_CURRENT, _shift); + float _height = chart3d.GetPriceScale(_ohlc.GetMaxOC()) - chart3d.GetPriceScale(_ohlc.GetMinOC()); + float higher = _ohlc.IsBear(); + cube1.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); - cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.open); - cube1.Ptr().GetMaterial().SetColor(0xFF0000); + cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetMinOC()) + _height / 2; + cube1.Ptr().GetTSR().scale.y = _height; + + //Print(cube1.Ptr().GetTSR().translation.y); + + cube1.Ptr().GetMaterial().SetColor(higher ? 0x00FF00 : 0xFF0000); _device.Render(cube1.Ptr()); cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); - cube2.Ptr().GetTSR().scale.y = 10.0f; - cube2.Ptr().GetMaterial().SetColor(0xFF0000); + float _line_height = chart3d.GetPriceScale(_ohlc.GetHigh()) - chart3d.GetPriceScale(_ohlc.GetLow()); + cube2.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetLow()) + _line_height / 2; + cube2.Ptr().GetTSR().scale.y = _line_height; + cube2.Ptr().GetMaterial().SetColor(0x8888888); _device.Render(cube2.Ptr()); } + + // Rendering price lines. + if (true) + for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 5.55f) { + float _y = chart3d.GetPriceScale(_s); + + cube3.Ptr().GetTSR().translation.y = _y; + cube3.Ptr().GetTSR().scale.x = 200.0f; + + cube3.Ptr().GetMaterial().SetColor(0xFFFFFFFF); + _device.Render(cube3.Ptr()); + } } }; \ No newline at end of file diff --git a/3D/Device.h b/3D/Device.h index 5fd811132..c492f6df2 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -194,9 +194,11 @@ class Device : public Dynamic { IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); - PushTransform(_mesh.GetTSR()); SetMaterial(_mesh.GetMaterial()); + + PushTransform(_mesh.GetTSR()); + SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS()); SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS()); @@ -229,14 +231,7 @@ class Device : public Dynamic { int Height() { return frontend.Ptr().Height(); } void SetCameraOrtho3D(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) { - DXMatrixOrthoLH(mtx_view, 1.0f, 1.0f / Width() * Height(), -10000, 10000); - mtx_view.m[3][3] = _pos_z; - DXMatrix _translate; - DXMatrix _scale; - DXMatrixTranslation(_translate, _pos_x, _pos_y, 0.0f); - DXMatrixTranslation(_scale, 1.0f / _pos_z, 1.0f / _pos_z, 0.0f); - // DXMatrixMultiply(mtx_view, _translate, mtx_view); - // DXMatrixMultiply(mtx_view, mtx_view, _scale); + DXMatrixOrthoLH(mtx_projection, 1.0f * _pos_z, 1.0f / Width() * Height() * _pos_z, -10000, 10000); } DXMatrix GetWorldMatrix() { return mtx_world; } diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 6c88f1347..d431ec171 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -142,7 +142,7 @@ class MT5Frontend : public Frontend { Print("ResourceCreate: LastError: ", GetLastError()); #endif ChartRedraw(); - Sleep(5); + Sleep(1); } /** diff --git a/3D/Material.h b/3D/Material.h new file mode 100644 index 000000000..1cb05704b --- /dev/null +++ b/3D/Material.h @@ -0,0 +1,18 @@ +#include "Math.h" + +/** + * Generic vertex to be used by meshes. + */ +class Material { + public: + DXColor Color; + + Material(unsigned int _color = 0xFFFFFFFF) { Color = DXColor(_color); } + + Material(const Material& _r) { Color = _r.Color; } + + Material* SetColor(unsigned int _color) { + Color = DXColor(_color); + return &this; + } +}; diff --git a/3D/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl index beaeada19..6218a4748 100644 --- a/3D/Shaders/cube_ps.hlsl +++ b/3D/Shaders/cube_ps.hlsl @@ -6,6 +6,12 @@ struct INPUT { }; float4 main(INPUT input) : SV_TARGET { - float4 ambient = {0.0, 0.2, 0.4, 1.0}; - return ambient + input.color * saturate(dot(input.lightdir, input.normal)); + float4 ambient = {0.0, 0.1, 0.3, 1.0}; + input.color.a = 1.0f; + float ambient_contribution = 0.1f; + float diffuse_contribution = 0.6f; + float lighting_contribution = 1.0f - diffuse_contribution - ambient_contribution; + + return ambient_contribution * ambient + diffuse_contribution * input.color + + lighting_contribution * input.color * saturate(dot(input.lightdir, input.normal)); } diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl index a4928a1d7..c28c1b513 100644 --- a/3D/Shaders/cube_vs.hlsl +++ b/3D/Shaders/cube_vs.hlsl @@ -22,7 +22,7 @@ struct OUTPUT { OUTPUT main(INPUT input) { OUTPUT output; - matrix mvp = mul(mul(world, view), projection); + matrix mvp = mul(mul(view, world), projection); output.position = mul(input.position, mvp); output.normal = normalize(mul(input.normal, world)); diff --git a/3D/TSR.h b/3D/TSR.h index d56f8ecc3..88b586693 100644 --- a/3D/TSR.h +++ b/3D/TSR.h @@ -54,8 +54,8 @@ class TSR { DXMatrixIdentity(_mtx_result); DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_1); DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_rotation_2); - DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation); DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_scale); + DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation); return _mtx_result; } diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 5ed5a0f9b..8809ab565 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -35,6 +35,10 @@ //#define Print if (false) Print // Includes. +#include "../Serializer.mqh" +#include "../Test.mqh" +#include "../BufferStruct.mqh" +#include "../Chart.mqh" #include "../3D/Chart3D.h" #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" @@ -42,13 +46,30 @@ #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../3D/Frontends/MT5Frontend.h" -#include "../Chart.mqh" -#include "../Serializer.mqh" -#include "../Test.mqh" // int OnStart() { return OnInit(); } -BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { return Chart::GetOHLC(_tf, _shift); } +BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { + static Chart _chart(_tf); + static BufferStruct idata; + + long _bar_time = _chart.GetBarTime(_shift); + unsigned int _position; + IndicatorDataEntry _entry(4); + if (idata.KeyExists(_bar_time, _position)) { + _entry = idata.GetByPos(_position); + } else { + _entry.timestamp = _chart.GetBarTime(_tf, _shift); + _entry.values[0] = (float)_chart.GetOpen(_tf, _shift); + _entry.values[1] = (float)_chart.GetHigh(_tf, _shift); + _entry.values[2] = (float)_chart.GetLow(_tf, _shift); + _entry.values[3] = (float)_chart.GetClose(_tf, _shift); + _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); + idata.Add(_entry, _bar_time); + } + + return BarOHLC(_entry.GetValue(0), _entry.GetValue(1), _entry.GetValue(2), _entry.GetValue(3)); +} int OnInit() { return OnStart(); } @@ -75,7 +96,7 @@ int OnStart() { unsigned int _rand_color = rand() * 1256; - gfx.SetCameraOrtho3D(0.0f, 0.0f, 20.0f); + gfx.SetCameraOrtho3D(0.0f, 0.0f, 80.0f); gfx.SetLightDirection(0.0f, 0.0f, -1.0f); while (!IsStopped()) { @@ -86,11 +107,11 @@ int OnStart() { gfx.Begin(0x777255EE); static float x = 0; - x += 0.0f; + x += 0.15f; TSR tsr; - tsr.rotation.y = sin(x) / 3; - tsr.rotation.x = sin(x / 4) / 3; + tsr.rotation.y = sin(x) / 4; + tsr.rotation.x = sin(x / 2) * 0.3f; gfx.PushTransform(tsr); _chart.Ptr().Render(gfx); From c4a8ab44809130e027447d849fc347f42cffa91f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Sat, 15 May 2021 16:19:30 +0200 Subject: [PATCH 23/97] WIP. --- 3D/Chart3D.h | 49 +++++++++++++++++++++++++++------------------ 3D/Chart3DCandles.h | 13 ++++++------ Chart.struct.h | 7 ++++--- Util.h | 9 +++++++++ tests/3DTest.mq5 | 19 +++++++++--------- 5 files changed, 59 insertions(+), 38 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index fdafdf0ac..d2e182c85 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -29,6 +29,7 @@ #include "../Refs.mqh" #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" +#include "../Indicators/Indi_MA.mqh" #include "Chart3DCandles.h" #include "Chart3DType.h" #include "Cube.h" @@ -114,43 +115,53 @@ class Chart3D : public Dynamic { return renderers[type].Ptr(); } + /** + * Returns given bar's OHLC. + */ BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } + /** + * Return first shift that are visible on the screen. Values is away from 0. + */ int GetBarsVisibleShiftStart() { return 80; } + /** + * Return last shift that are visible on the screen. Value is closer to 0. + */ int GetBarsVisibleShiftEnd() { return 0; } + /** + * Returns lowest price of bars on the screen. + */ float GetMinBarsPrice() { - float _min = 100.0f; - for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { - BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); - if (_ohlc.GetMinOC() < _min) { - _min = _ohlc.GetMinOC(); - } - } - return _min; + return ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } + /** + * Returns highest price of bars on the screen. + */ float GetMaxBarsPrice() { - float _max = -100.0f; - for (int _shift = GetBarsVisibleShiftStart(); _shift != GetBarsVisibleShiftEnd(); --_shift) { - BarOHLC _ohlc = GetPrice(PERIOD_CURRENT, _shift); - if (_ohlc.GetMaxOC() > _max) { - _max = _ohlc.GetMaxOC(); - } - } - return _max; + return ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } + /** + * Returns number of bars that are visible on te screen. + */ int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; } - float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.25f / 2.0f + 1.25f * _shift; } + /** + * Returns absolute x coordinate of bar on the screen. Must not be affected by camera's x offset. + */ + float GetBarPositionX(int _shift) { return -(float)GetBarsVisibleCount() * 1.35f / 2.0f + 1.35f * _shift; } + /** + * Returns y coordinate of price on the screen. Takes into consideration zoom and min/max prices on the screen. + */ float GetPriceScale(float price) { - float _scale_y = 20.0f; + float _scale_y = 40.0f; float _price_min = GetMinBarsPrice(); float _price_max = GetMaxBarsPrice(); - float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y; + float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y - (_scale_y / 2); return _result; } diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index c230003c1..3532407ce 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -46,8 +46,8 @@ class Chart3DCandles : public Chart3DType { */ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) { cube1 = new Cube(1.0f, 1.0f, 1.0f); - cube2 = new Cube(0.15f, 1.0f, 0.15f); - cube3 = new Cube(1.0f, 0.15f, 0.15f); + cube2 = new Cube(0.10f, 1.0f, 0.10f); + cube3 = new Cube(1.0f, 0.075f, 0.075f); } /** @@ -68,26 +68,25 @@ class Chart3DCandles : public Chart3DType { //Print(cube1.Ptr().GetTSR().translation.y); - cube1.Ptr().GetMaterial().SetColor(higher ? 0x00FF00 : 0xFF0000); + cube1.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube1.Ptr()); cube2.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); float _line_height = chart3d.GetPriceScale(_ohlc.GetHigh()) - chart3d.GetPriceScale(_ohlc.GetLow()); cube2.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetLow()) + _line_height / 2; cube2.Ptr().GetTSR().scale.y = _line_height; - cube2.Ptr().GetMaterial().SetColor(0x8888888); + cube2.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube2.Ptr()); } // Rendering price lines. - if (true) - for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 5.55f) { + for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 0.0001f) { float _y = chart3d.GetPriceScale(_s); cube3.Ptr().GetTSR().translation.y = _y; cube3.Ptr().GetTSR().scale.x = 200.0f; - cube3.Ptr().GetMaterial().SetColor(0xFFFFFFFF); + cube3.Ptr().GetMaterial().SetColor(0x333333); _device.Render(cube3.Ptr()); } } diff --git a/Chart.struct.h b/Chart.struct.h index e17f8408e..4e729db66 100644 --- a/Chart.struct.h +++ b/Chart.struct.h @@ -38,6 +38,7 @@ class Class; #include "Chart.define.h" #include "Chart.enum.h" #include "Chart.struct.tf.h" +#include "Util.h" #include "Serializer.mqh" #include "Terminal.define.h" @@ -352,15 +353,15 @@ struct ChartStatic { case MODE_VOLUME: ArraySetAsSeries(arr_l, true); CopyTickVolume(_symbol, _tf, _start, _count, arr_l); - return (ArrayMinimum(arr_l, 0, _count) + _start); + return ArrayMinimum(arr_l, 0, _count) + _start; case MODE_TIME: ArraySetAsSeries(arr_dt, true); CopyTime(_symbol, _tf, _start, _count, arr_dt); - return (ArrayMinimum(arr_dt, 0, _count) + _start); + return ArrayMinimum(arr_dt, 0, _count) + _start; default: break; } - return (ArrayMinimum(arr_d, 0, _count) + _start); + return ArrayMinimum(arr_d, 0, _count) + _start; #endif } diff --git a/Util.h b/Util.h index 06676caf0..3933d9d46 100644 --- a/Util.h +++ b/Util.h @@ -53,4 +53,13 @@ class Util { ::ArrayResize(_array, ArraySize(_array) - 1); return _result; } + + template + static T Print(T& _array[]) { + string _result; + for (int i = 0; i < ArraySize(_array); ++i) { + _result += IntegerToString(i) + ": " + (string)_array[i]; + } + return _result; + } }; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 8809ab565..a9d1d07af 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -49,8 +49,9 @@ // int OnStart() { return OnInit(); } + BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { - static Chart _chart(_tf); + static Chart _chart(); static BufferStruct idata; long _bar_time = _chart.GetBarTime(_shift); @@ -59,11 +60,11 @@ BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { if (idata.KeyExists(_bar_time, _position)) { _entry = idata.GetByPos(_position); } else { - _entry.timestamp = _chart.GetBarTime(_tf, _shift); - _entry.values[0] = (float)_chart.GetOpen(_tf, _shift); - _entry.values[1] = (float)_chart.GetHigh(_tf, _shift); - _entry.values[2] = (float)_chart.GetLow(_tf, _shift); - _entry.values[3] = (float)_chart.GetClose(_tf, _shift); + _entry.timestamp = _chart.GetBarTime(_shift); + _entry.values[0] = (float)_chart.GetOpen(_shift); + _entry.values[1] = (float)_chart.GetHigh(_shift); + _entry.values[2] = (float)_chart.GetLow(_shift); + _entry.values[3] = (float)_chart.GetClose(_shift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); idata.Add(_entry, _bar_time); } @@ -96,7 +97,7 @@ int OnStart() { unsigned int _rand_color = rand() * 1256; - gfx.SetCameraOrtho3D(0.0f, 0.0f, 80.0f); + gfx.SetCameraOrtho3D(0.0f, 0.0f, 100.0f); gfx.SetLightDirection(0.0f, 0.0f, -1.0f); while (!IsStopped()) { @@ -104,10 +105,10 @@ int OnStart() { break; } - gfx.Begin(0x777255EE); + gfx.Begin(0x00FFFFFF); static float x = 0; - x += 0.15f; + x += 0.025f; TSR tsr; tsr.rotation.y = sin(x) / 4; From 8edb9157a1ea39d4d5337278053b6e6d0f771ade Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 19 May 2021 22:40:54 +0200 Subject: [PATCH 24/97] WIP. Somehow chart events doesn't work. --- 3D/Chart3D.h | 38 +++++++++-- 3D/Chart3DCandles.h | 13 +++- 3D/Chart3DType.h | 4 ++ 3D/Device.h | 36 ++++++++++- 3D/Frontend.h | 40 ++++++++++++ 3D/Frontends/MT5Frontend.h | 16 +++++ 3D/Interface.h | 129 +++++++++++++++++++++++++++++++++++++ Instances.h | 51 +++++++++++++++ Util.h | 16 ++++- tests/3DTest.mq5 | 6 +- 10 files changed, 338 insertions(+), 11 deletions(-) create mode 100644 3D/Interface.h create mode 100644 Instances.h diff --git a/3D/Chart3D.h b/3D/Chart3D.h index d2e182c85..a0bf9f9f7 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -30,10 +30,12 @@ #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" #include "../Indicators/Indi_MA.mqh" +#include "../Instances.h" #include "Chart3DCandles.h" #include "Chart3DType.h" #include "Cube.h" #include "Device.h" +#include "Interface.h" // Resources. #resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; @@ -48,6 +50,13 @@ enum ENUM_CHART3D_TYPE { CHART3D_TYPE_LINES, }; +class Chart3D; + +void chart3d_interface_listener(InterfaceEvent& _event, void* _target) { + Chart3D* chart3d = (Chart3D*)_target; + chart3d.OnInterfaceEvent(_event); +} + /** * 3D chart renderer. */ @@ -70,22 +79,41 @@ class Chart3D : public Dynamic { // Shaders. Ref shader_vs; Ref shader_ps; + + Chart3DType* current_renderer; + + Instances instances; public: /** * Constructor. */ - Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) { + Chart3D(Chart3DPriceFetcher _price_fetcher, ENUM_CHART3D_TYPE _type = CHART3D_TYPE_CANDLES) : instances(&this) { price_fetcher = _price_fetcher; type = _type; offset.x = offset.y = 0.0f; offset.z = 25.0f; initialized = false; + Interface::AddListener(chart3d_interface_listener, &this); } - + + void OnInterfaceEvent(InterfaceEvent& _event) { + if (GetCurrentRenderer() == NULL) { + return; + } + + Device* _gfx = GetCurrentRenderer().GetDevice(); + + _gfx.DrawText(10, 10, "Event!"); + } + Shader* GetShaderVS() { return shader_vs.Ptr(); } Shader* GetShaderPS() { return shader_ps.Ptr(); } + + Chart3DType* GetCurrentRenderer() { + return current_renderer; + } Chart3DType* GetRenderer(Device* _device) { if (!initialized) { @@ -111,6 +139,8 @@ class Chart3D : public Dynamic { return NULL; } } + + current_renderer = renderers[type].Ptr(); return renderers[type].Ptr(); } @@ -134,14 +164,14 @@ class Chart3D : public Dynamic { * Returns lowest price of bars on the screen. */ float GetMinBarsPrice() { - return ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + return (float)ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } /** * Returns highest price of bars on the screen. */ float GetMaxBarsPrice() { - return ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + return (float)ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } /** diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 3532407ce..fbab65553 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -79,13 +79,22 @@ class Chart3DCandles : public Chart3DType { _device.Render(cube2.Ptr()); } + int _digits = (int)MarketInfo(Symbol(), MODE_DIGITS); + float _pip_pow = (float)MathPow(10, _digits); + float _pip_size = 1.0f / (float)MathPow(10, _digits); + float _pip_size_m1 = 1.0f / (float)MathPow(10, _digits - 1); + float _start = float(int(chart3d.GetMinBarsPrice() * _pip_pow) * _pip_size); + float _end = float(int(chart3d.GetMaxBarsPrice() * _pip_pow) * _pip_size); + // Rendering price lines. - for (float _s = chart3d.GetMinBarsPrice(); _s <= chart3d.GetMaxBarsPrice(); _s += 0.0001f) { - float _y = chart3d.GetPriceScale(_s); + for (double _s = _start; _s < _end + _pip_size_m1; _s += _pip_size * 10) { + float _y = chart3d.GetPriceScale((float)_s); cube3.Ptr().GetTSR().translation.y = _y; cube3.Ptr().GetTSR().scale.x = 200.0f; + _device.DrawText(5, _y, StringFormat("%." + IntegerToString(_digits) + "f", _s), 0x90FFFFFF, TA_LEFT | TA_VCENTER, GFX_DRAW_TEXT_FLAG_2D_COORD_X); + cube3.Ptr().GetMaterial().SetColor(0x333333); _device.Render(cube3.Ptr()); } diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h index d96de2463..122444dbd 100644 --- a/3D/Chart3DType.h +++ b/3D/Chart3DType.h @@ -44,6 +44,10 @@ class Chart3DType : public Dynamic { * Constructor. */ Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {} + + Device* GetDevice() { + return device; + } /** * Renders chart. diff --git a/3D/Device.h b/3D/Device.h index c492f6df2..d449565a5 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -35,6 +35,12 @@ #include "Shader.h" #include "VertexBuffer.h" +enum GFX_DRAW_TEXT_FLAGS { + GFX_DRAW_TEXT_FLAG_NONE, + GFX_DRAW_TEXT_FLAG_2D_COORD_X, + GFX_DRAW_TEXT_FLAG_2D_COORD_Y +}; + enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; /** @@ -90,6 +96,7 @@ class Device : public Dynamic { Device* End() { RenderEnd(); frontend.Ptr().RenderEnd(context); + frontend.Ptr().ProcessDrawText(); return &this; } @@ -254,6 +261,33 @@ class Device : public Dynamic { lightdir.z = z; } + /** + * Enqueues text to be drawn directly into the pixel buffer. Queue will be processed in the Device::End() method. + */ + void DrawText(float _x, float _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0, unsigned int _flags = 0) { + DViewport _viewport; + _viewport.x = 0; + _viewport.y = 0; + _viewport.width = frontend.Ptr().Width(); + _viewport.height = frontend.Ptr().Height(); + _viewport.minz = -10000.0f; + _viewport.maxz = 10000.0f; + + DXVector3 _vec3_in(_x, _y, 0.0f); + DXVector3 _vec3_out; + DXVec3Project(_vec3_out, _vec3_in, _viewport, GetProjectionMatrix(), GetViewMatrix(), GetWorldMatrix()); + + if ((_flags & GFX_DRAW_TEXT_FLAG_2D_COORD_X) == GFX_DRAW_TEXT_FLAG_2D_COORD_X) { + _vec3_out.x = _x; + } + + if ((_flags & GFX_DRAW_TEXT_FLAG_2D_COORD_Y) == GFX_DRAW_TEXT_FLAG_2D_COORD_Y) { + _vec3_out.y = _y; + } + + frontend.Ptr().DrawText(_vec3_out.x, _vec3_out.y, _text, _color, _align); + } + protected: /** * Initializes graphics device. @@ -279,4 +313,4 @@ class Device : public Dynamic { * Clears color buffer. */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color) = NULL; -}; \ No newline at end of file +}; diff --git a/3D/Frontend.h b/3D/Frontend.h index 6edbec4bf..5757e7893 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -27,10 +27,22 @@ #include "../Refs.mqh" +struct DrawTextQueueItem { + float x; + float y; + string text; + unsigned int rgb; + unsigned int align; +}; + /** * Represents visual target (OS window/canvas for rendering). */ class Frontend : public Dynamic { + protected: + + DrawTextQueueItem draw_text_queue[]; + public: /** * Initializes canvas. @@ -71,4 +83,32 @@ class Frontend : public Dynamic { * Returns canvas' height. */ virtual int Height() = NULL; + + /** + * Enqueues text to be drawn directly into the pixel buffer. Queue will be processed in the Device::End() method. + */ + virtual void DrawText(float _x, float _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) { + DrawTextQueueItem _item; + _item.x = _x; + _item.y = _y; + _item.text = _text; + _item.rgb = _color; + _item.align = _align; + Util::ArrayPush(draw_text_queue, _item); + } + + void ProcessDrawText() { + for (int i = 0; i < ArraySize(draw_text_queue); ++i) { + DrawTextQueueItem _item = draw_text_queue[i]; + DrawTextNow((int)_item.x, (int)_item.y, _item.text, _item.rgb, _item.align); + } + ArrayResize(draw_text_queue, 0); + } + +protected: + + /** + * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. + */ + virtual void DrawTextNow(int _x, int _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) {} }; \ No newline at end of file diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index d431ec171..f57b70a9d 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -134,6 +134,7 @@ class MT5Frontend : public Frontend { Print("MT5Frontend: DXContextGetColors()"); #endif DXContextGetColors(context, image); + ProcessDrawText(); #ifdef __debug__ Print("DXContextGetColors: LastError: ", GetLastError()); #endif @@ -154,4 +155,19 @@ class MT5Frontend : public Frontend { * Returns canvas' height. */ virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } + + /** + * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. + */ + virtual void DrawTextNow(int _x, int _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) { + TextSetFont("Arial", -80, FW_EXTRABOLD, 0); + #ifdef __debug__ + Print("TextSetFont: LastError = ", GetLastError()); + #endif + + TextOut(_text, _x, _y, _align, image, Width(), Height(), _color, COLOR_FORMAT_ARGB_NORMALIZE); + #ifdef __debug__ + Print("TextOut: LastError = ", GetLastError()); + #endif + } }; \ No newline at end of file diff --git a/3D/Interface.h b/3D/Interface.h new file mode 100644 index 000000000..5bacb1d8b --- /dev/null +++ b/3D/Interface.h @@ -0,0 +1,129 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, 31337 Investments Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Chart events. + */ + +#include "../Util.h" + +enum ENUM_INTERFACE_EVENT { + INTERFACE_EVENT_NONE, + INTERFACE_EVENT_MOUSE_MOVE, + INTERFACE_EVENT_MOUSE_DOWN, + INTERFACE_EVENT_MOUSE_UP +}; + +struct InterfaceEvent { + ENUM_INTERFACE_EVENT type; + struct EventMouse { + int x; + int y; + datetime dt; + }; + + union EventData { + EventMouse mouse; + } data; +}; + + +void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { + datetime _dt; + double _mp; + int _window = 0; + InterfaceEvent _event; + + + if (id == CHART_EVENT_MOUSE_MOVE) { + Interface::mouse_pos_x = (int)lparam; + Interface::mouse_pos_y = (int)dparam; + ChartXYToTimePrice(0, Interface::mouse_pos_x, Interface::mouse_pos_y, _window, _dt, _mp); + _event.type = INTERFACE_EVENT_MOUSE_MOVE; + _event.data.mouse.x = Interface::mouse_pos_x; + _event.data.mouse.y = Interface::mouse_pos_y; + Interface::FireEvent(_event); + } +} + +typedef void (*InterfaceListener)(InterfaceEvent&, void*); + +class Interface +{ + public: + + struct Installation + { + InterfaceListener listener; + void* target; + }; + + static Installation installations[]; + + static bool mouse_was_down; + static int mouse_pos_x; + static int mouse_pos_y; + static bool initialized; + + static void AddListener(InterfaceListener _listener, void* _target) { + if (!initialized) { + ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); + ChartRedraw(); + initialized = true; + } + + for (int i = 0; i < ArraySize(installations); ++i) { + if (installations[i].listener == _listener) { + // Listener already added. + return; + } + } + + Installation _installation; + _installation.listener = _listener; + _installation.target = _target; + + Util::ArrayPush(installations, _installation); + } + + static void FireEvent(InterfaceEvent& _event) { + for (int i = 0; i < ArraySize(installations); ++i) { + Installation _installation = installations[i]; + _installation.listener(_event, _installation.target); + } + } + + static int GetMouseX() { + return mouse_pos_x; + } + + static int GetMouseY() { + return mouse_pos_y; + } +}; + +Interface::Installation Interface::installations[]; +bool Interface::mouse_was_down = false; +int Interface::mouse_pos_x = 0; +int Interface::mouse_pos_y = 0; +bool Interface::initialized = false; diff --git a/Instances.h b/Instances.h new file mode 100644 index 000000000..ed1c264d8 --- /dev/null +++ b/Instances.h @@ -0,0 +1,51 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Collects information about class instances. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +#include "Dict.mqh" +#include "Util.h" + +template +class Instances { +public: + + static T* instances[]; + Instances(T* _self) { + Util::ArrayPush(instances, _self); + } + + ~Instances() { + //Util::ArrayRemove(instances, &this); + } +}; + +template +T* Instances::instances[]; \ No newline at end of file diff --git a/Util.h b/Util.h index 3933d9d46..e03176268 100644 --- a/Util.h +++ b/Util.h @@ -38,7 +38,7 @@ class Util { * Pushes item into the native array and reserves space for further items by some fixed step. */ template - static int ArrayPush(T& _array[], const V& _value, int _resize_pool = 32) { + static int ArrayPush(T& _array[], V& _value, int _resize_pool = 32) { Util::ArrayResize(_array, ArraySize(_array) + 1, _resize_pool); _array[ArraySize(_array) - 1] = _value; return ArraySize(_array) - 1; @@ -62,4 +62,18 @@ class Util { } return _result; } + + /** + * Checks whether array has given value. + */ + template + static bool ArrayContains(T& _array[], const V& _value) { + for (int i = 0; i < ArraySize(_array); ++i) { + if (_array[i] == _value) { + return true; + } + } + + return false; + } }; \ No newline at end of file diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index a9d1d07af..5ba1014e7 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -111,9 +111,9 @@ int OnStart() { x += 0.025f; TSR tsr; - tsr.rotation.y = sin(x) / 4; - tsr.rotation.x = sin(x / 2) * 0.3f; - + //tsr.rotation.y = (float)sin(x) / 4.0f; + tsr.rotation.x = (float)sin(x / 2); + gfx.PushTransform(tsr); _chart.Ptr().Render(gfx); gfx.PopTransform(); From cc1b47b4a8abbd25fea3fd1cea8e2f4e71f75a5d Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 3 Aug 2021 21:39:12 +0100 Subject: [PATCH 25/97] Strategy: Adds GetIndicators() --- Strategy.mqh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Strategy.mqh b/Strategy.mqh index 244fff438..a72b57b82 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -325,6 +325,11 @@ class Strategy : public Object { */ Indicator *GetIndicator(int _id = 0) { return sparams.GetIndicator(_id); } + /** + * Returns strategy's indicators. + */ + DictStruct> GetIndicators() { return sparams.indicators_managed; } + /* Struct getters */ /** From fdf40872588f1d7f905df602374f1b7785a6e9ca Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 11 Sep 2021 15:21:26 +0100 Subject: [PATCH 26/97] 3DTest: Fixes warning: OnInit function is useless for scripts --- 3D/Chart3D.h | 18 +++++++-------- 3D/Chart3DCandles.h | 14 ++++++------ 3D/Chart3DType.h | 4 ++-- 3D/Cube.h | 2 +- 3D/Device.h | 6 ++--- 3D/Devices/MTDX/MTDXDevice.h | 2 +- 3D/Devices/MTDX/MTDXIndexBuffer.h | 2 +- 3D/Devices/MTDX/MTDXShader.h | 2 +- 3D/Devices/MTDX/MTDXVertexBuffer.h | 2 +- 3D/Face.h | 2 +- 3D/Frontend.h | 6 ++--- 3D/Frontends/MT5Frontend.h | 6 ++--- 3D/IndexBuffer.h | 2 +- 3D/Interface.h | 30 ++++++++++++------------- 3D/Mesh.h | 2 +- 3D/Shader.h | 2 +- 3D/Shaders/cube_vs.hlsl | 2 +- 3D/TSR.h | 2 +- 3D/VertexBuffer.h | 2 +- Instances.h | 2 +- Util.h | 6 ++--- tests/3D/Shaders/vertex.hlsl | 10 ++++----- tests/3DTest.mq5 | 36 +++++++++++++----------------- 23 files changed, 78 insertions(+), 84 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index a0bf9f9f7..86175fd55 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -79,9 +79,9 @@ class Chart3D : public Dynamic { // Shaders. Ref shader_vs; Ref shader_ps; - + Chart3DType* current_renderer; - + Instances instances; public: @@ -96,21 +96,21 @@ class Chart3D : public Dynamic { initialized = false; Interface::AddListener(chart3d_interface_listener, &this); } - + void OnInterfaceEvent(InterfaceEvent& _event) { if (GetCurrentRenderer() == NULL) { return; } - + Device* _gfx = GetCurrentRenderer().GetDevice(); - + _gfx.DrawText(10, 10, "Event!"); } - + Shader* GetShaderVS() { return shader_vs.Ptr(); } Shader* GetShaderPS() { return shader_ps.Ptr(); } - + Chart3DType* GetCurrentRenderer() { return current_renderer; } @@ -139,7 +139,7 @@ class Chart3D : public Dynamic { return NULL; } } - + current_renderer = renderers[type].Ptr(); return renderers[type].Ptr(); @@ -209,4 +209,4 @@ class Chart3D : public Dynamic { _type_renderer.Render(_device); } -}; \ No newline at end of file +}; diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index fbab65553..8598dec5b 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -65,9 +65,9 @@ class Chart3DCandles : public Chart3DType { cube1.Ptr().GetTSR().translation.x = chart3d.GetBarPositionX(_shift); cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetMinOC()) + _height / 2; cube1.Ptr().GetTSR().scale.y = _height; - + //Print(cube1.Ptr().GetTSR().translation.y); - + cube1.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube1.Ptr()); @@ -78,25 +78,25 @@ class Chart3DCandles : public Chart3DType { cube2.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube2.Ptr()); } - + int _digits = (int)MarketInfo(Symbol(), MODE_DIGITS); float _pip_pow = (float)MathPow(10, _digits); float _pip_size = 1.0f / (float)MathPow(10, _digits); float _pip_size_m1 = 1.0f / (float)MathPow(10, _digits - 1); float _start = float(int(chart3d.GetMinBarsPrice() * _pip_pow) * _pip_size); float _end = float(int(chart3d.GetMaxBarsPrice() * _pip_pow) * _pip_size); - + // Rendering price lines. for (double _s = _start; _s < _end + _pip_size_m1; _s += _pip_size * 10) { float _y = chart3d.GetPriceScale((float)_s); cube3.Ptr().GetTSR().translation.y = _y; cube3.Ptr().GetTSR().scale.x = 200.0f; - + _device.DrawText(5, _y, StringFormat("%." + IntegerToString(_digits) + "f", _s), 0x90FFFFFF, TA_LEFT | TA_VCENTER, GFX_DRAW_TEXT_FLAG_2D_COORD_X); - + cube3.Ptr().GetMaterial().SetColor(0x333333); _device.Render(cube3.Ptr()); } } -}; \ No newline at end of file +}; diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h index 122444dbd..66e458212 100644 --- a/3D/Chart3DType.h +++ b/3D/Chart3DType.h @@ -44,7 +44,7 @@ class Chart3DType : public Dynamic { * Constructor. */ Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {} - + Device* GetDevice() { return device; } @@ -53,4 +53,4 @@ class Chart3DType : public Dynamic { * Renders chart. */ virtual void Render(Device* _device) {} -}; \ No newline at end of file +}; diff --git a/3D/Cube.h b/3D/Cube.h index 5d0c69d45..b4070b7f3 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -77,4 +77,4 @@ class Cube : public Mesh { SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); } -}; \ No newline at end of file +}; diff --git a/3D/Device.h b/3D/Device.h index d449565a5..eb54420a2 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -272,11 +272,11 @@ class Device : public Dynamic { _viewport.height = frontend.Ptr().Height(); _viewport.minz = -10000.0f; _viewport.maxz = 10000.0f; - + DXVector3 _vec3_in(_x, _y, 0.0f); DXVector3 _vec3_out; DXVec3Project(_vec3_out, _vec3_in, _viewport, GetProjectionMatrix(), GetViewMatrix(), GetWorldMatrix()); - + if ((_flags & GFX_DRAW_TEXT_FLAG_2D_COORD_X) == GFX_DRAW_TEXT_FLAG_2D_COORD_X) { _vec3_out.x = _x; } @@ -284,7 +284,7 @@ class Device : public Dynamic { if ((_flags & GFX_DRAW_TEXT_FLAG_2D_COORD_Y) == GFX_DRAW_TEXT_FLAG_2D_COORD_Y) { _vec3_out.y = _y; } - + frontend.Ptr().DrawText(_vec3_out.x, _vec3_out.y, _text, _color, _align); } diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h index 6200f1b36..7bb1c93b8 100644 --- a/3D/Devices/MTDX/MTDXDevice.h +++ b/3D/Devices/MTDX/MTDXDevice.h @@ -154,4 +154,4 @@ class MTDXDevice : public Device { #endif } } -}; \ No newline at end of file +}; diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h index 60b33124f..6662aacab 100644 --- a/3D/Devices/MTDX/MTDXIndexBuffer.h +++ b/3D/Devices/MTDX/MTDXIndexBuffer.h @@ -66,4 +66,4 @@ class MTDXIndexBuffer : public IndexBuffer { Print("Select: LastError: ", GetLastError()); #endif } -}; \ No newline at end of file +}; diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index 6a5b951c4..dbde130ad 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -196,4 +196,4 @@ class MTDXShader : public Shader { DXInputSet(cbuffer_mvp_handle, mvp_buffer); DXShaderSet(GetDevice().Context(), handle); } -}; \ No newline at end of file +}; diff --git a/3D/Devices/MTDX/MTDXVertexBuffer.h b/3D/Devices/MTDX/MTDXVertexBuffer.h index 915d60979..e96b9c7b7 100644 --- a/3D/Devices/MTDX/MTDXVertexBuffer.h +++ b/3D/Devices/MTDX/MTDXVertexBuffer.h @@ -60,4 +60,4 @@ class MTDXVertexBuffer : public VertexBuffer { Print("Select: LastError: ", GetLastError()); #endif } -}; \ No newline at end of file +}; diff --git a/3D/Face.h b/3D/Face.h index 76b87e26b..558c0bc4e 100644 --- a/3D/Face.h +++ b/3D/Face.h @@ -93,4 +93,4 @@ struct Face { points[i].Normal = _normal; } } -}; \ No newline at end of file +}; diff --git a/3D/Frontend.h b/3D/Frontend.h index 5757e7893..1870fb9bd 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -40,7 +40,7 @@ struct DrawTextQueueItem { */ class Frontend : public Dynamic { protected: - + DrawTextQueueItem draw_text_queue[]; public: @@ -96,7 +96,7 @@ class Frontend : public Dynamic { _item.align = _align; Util::ArrayPush(draw_text_queue, _item); } - + void ProcessDrawText() { for (int i = 0; i < ArraySize(draw_text_queue); ++i) { DrawTextQueueItem _item = draw_text_queue[i]; @@ -111,4 +111,4 @@ class Frontend : public Dynamic { * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. */ virtual void DrawTextNow(int _x, int _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) {} -}; \ No newline at end of file +}; diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index f57b70a9d..723e2c2be 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -155,7 +155,7 @@ class MT5Frontend : public Frontend { * Returns canvas' height. */ virtual int Height() { return (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); } - + /** * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. */ @@ -164,10 +164,10 @@ class MT5Frontend : public Frontend { #ifdef __debug__ Print("TextSetFont: LastError = ", GetLastError()); #endif - + TextOut(_text, _x, _y, _align, image, Width(), Height(), _color, COLOR_FORMAT_ARGB_NORMALIZE); #ifdef __debug__ Print("TextOut: LastError = ", GetLastError()); #endif } -}; \ No newline at end of file +}; diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h index fef406675..fdd83d91e 100644 --- a/3D/IndexBuffer.h +++ b/3D/IndexBuffer.h @@ -60,4 +60,4 @@ class IndexBuffer : public Dynamic { * Activates index buffer for rendering. */ virtual void Select() = NULL; -}; \ No newline at end of file +}; diff --git a/3D/Interface.h b/3D/Interface.h index 5bacb1d8b..6ea02fba6 100644 --- a/3D/Interface.h +++ b/3D/Interface.h @@ -26,14 +26,14 @@ */ #include "../Util.h" - + enum ENUM_INTERFACE_EVENT { INTERFACE_EVENT_NONE, INTERFACE_EVENT_MOUSE_MOVE, INTERFACE_EVENT_MOUSE_DOWN, INTERFACE_EVENT_MOUSE_UP }; - + struct InterfaceEvent { ENUM_INTERFACE_EVENT type; struct EventMouse { @@ -41,20 +41,20 @@ struct InterfaceEvent { int y; datetime dt; }; - + union EventData { EventMouse mouse; } data; }; - + void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { datetime _dt; double _mp; int _window = 0; InterfaceEvent _event; - - + + if (id == CHART_EVENT_MOUSE_MOVE) { Interface::mouse_pos_x = (int)lparam; Interface::mouse_pos_y = (int)dparam; @@ -63,7 +63,7 @@ void OnChartEvent(const int id, const long& lparam, const double& dparam, const _event.data.mouse.x = Interface::mouse_pos_x; _event.data.mouse.y = Interface::mouse_pos_y; Interface::FireEvent(_event); - } + } } typedef void (*InterfaceListener)(InterfaceEvent&, void*); @@ -71,7 +71,7 @@ typedef void (*InterfaceListener)(InterfaceEvent&, void*); class Interface { public: - + struct Installation { InterfaceListener listener; @@ -79,40 +79,40 @@ class Interface }; static Installation installations[]; - + static bool mouse_was_down; static int mouse_pos_x; static int mouse_pos_y; static bool initialized; - + static void AddListener(InterfaceListener _listener, void* _target) { if (!initialized) { ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); ChartRedraw(); initialized = true; } - + for (int i = 0; i < ArraySize(installations); ++i) { if (installations[i].listener == _listener) { // Listener already added. return; } } - + Installation _installation; _installation.listener = _listener; _installation.target = _target; - + Util::ArrayPush(installations, _installation); } - + static void FireEvent(InterfaceEvent& _event) { for (int i = 0; i < ArraySize(installations); ++i) { Installation _installation = installations[i]; _installation.listener(_event, _installation.target); } } - + static int GetMouseX() { return mouse_pos_x; } diff --git a/3D/Mesh.h b/3D/Mesh.h index 94b8e9f0a..0ee82c0dc 100644 --- a/3D/Mesh.h +++ b/3D/Mesh.h @@ -253,4 +253,4 @@ class Mesh : public Dynamic { ibuff = _ibuff = _device.IndexBuffer(_indices); return true; } -}; \ No newline at end of file +}; diff --git a/3D/Shader.h b/3D/Shader.h index c586092de..51ae50504 100644 --- a/3D/Shader.h +++ b/3D/Shader.h @@ -105,4 +105,4 @@ class Shader : public Dynamic { * Selectes shader to be used by graphics device for rendering. */ virtual void Select() = NULL; -}; \ No newline at end of file +}; diff --git a/3D/Shaders/cube_vs.hlsl b/3D/Shaders/cube_vs.hlsl index c28c1b513..d9c651d7d 100644 --- a/3D/Shaders/cube_vs.hlsl +++ b/3D/Shaders/cube_vs.hlsl @@ -30,4 +30,4 @@ OUTPUT main(INPUT input) { output.color = input.color * mat_color; return output; -} \ No newline at end of file +} diff --git a/3D/TSR.h b/3D/TSR.h index 88b586693..ee015a01f 100644 --- a/3D/TSR.h +++ b/3D/TSR.h @@ -59,4 +59,4 @@ class TSR { return _mtx_result; } -}; \ No newline at end of file +}; diff --git a/3D/VertexBuffer.h b/3D/VertexBuffer.h index 8c979b384..822c33fb2 100644 --- a/3D/VertexBuffer.h +++ b/3D/VertexBuffer.h @@ -43,4 +43,4 @@ class VertexBuffer : public Dynamic { Device* GetDevice() { return device.Ptr(); } virtual void Select() = NULL; -}; \ No newline at end of file +}; diff --git a/Instances.h b/Instances.h index ed1c264d8..fee38cb80 100644 --- a/Instances.h +++ b/Instances.h @@ -48,4 +48,4 @@ class Instances { }; template -T* Instances::instances[]; \ No newline at end of file +T* Instances::instances[]; diff --git a/Util.h b/Util.h index e03176268..243b80752 100644 --- a/Util.h +++ b/Util.h @@ -53,7 +53,7 @@ class Util { ::ArrayResize(_array, ArraySize(_array) - 1); return _result; } - + template static T Print(T& _array[]) { string _result; @@ -73,7 +73,7 @@ class Util { return true; } } - + return false; } -}; \ No newline at end of file +}; diff --git a/tests/3D/Shaders/vertex.hlsl b/tests/3D/Shaders/vertex.hlsl index ab4715043..7df27058a 100644 --- a/tests/3D/Shaders/vertex.hlsl +++ b/tests/3D/Shaders/vertex.hlsl @@ -24,16 +24,16 @@ struct OUTPUT OUTPUT main(INPUT input) { OUTPUT output; - + input.position.w = 1.0f; - + matrix mvp = mul(mul(projection, view), world); - + output.position = mul(mvp, input.position); - + output.normal = normalize(mul(world, input.normal)); output.lightdir = lightdir; output.color = input.color; return output; -} \ No newline at end of file +} diff --git a/tests/3DTest.mq5 b/tests/3DTest.mq5 index 5ba1014e7..63390f3da 100644 --- a/tests/3DTest.mq5 +++ b/tests/3DTest.mq5 @@ -32,13 +32,7 @@ #resource "3D/Shaders/vertex.hlsl" as string ShaderSourceVS; #resource "3D/Shaders/pixel.hlsl" as string ShaderSourcePS; -//#define Print if (false) Print - // Includes. -#include "../Serializer.mqh" -#include "../Test.mqh" -#include "../BufferStruct.mqh" -#include "../Chart.mqh" #include "../3D/Chart3D.h" #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" @@ -46,9 +40,10 @@ #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../3D/Frontends/MT5Frontend.h" - -// int OnStart() { return OnInit(); } - +#include "../BufferStruct.mqh" +#include "../Chart.mqh" +#include "../Serializer.mqh" +#include "../Test.mqh" BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { static Chart _chart(); @@ -68,16 +63,15 @@ BarOHLC ChartPriceFeeder(ENUM_TIMEFRAMES _tf, int _shift) { _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, true); idata.Add(_entry, _bar_time); } - - return BarOHLC(_entry.GetValue(0), _entry.GetValue(1), _entry.GetValue(2), _entry.GetValue(3)); -} -int OnInit() { return OnStart(); } + return BarOHLC(_entry.GetValue(0), _entry.GetValue(1), _entry.GetValue(2), + _entry.GetValue(3)); +} /** - * Implements OnStart(). + * Implements OnInit(). */ -int OnStart() { +int OnInit() { Ref gfx_ptr = new MTDXDevice(); // Making a scope to ensure graphics device will be destructed as last. @@ -111,9 +105,9 @@ int OnStart() { x += 0.025f; TSR tsr; - //tsr.rotation.y = (float)sin(x) / 4.0f; + // tsr.rotation.y = (float)sin(x) / 4.0f; tsr.rotation.x = (float)sin(x / 2); - + gfx.PushTransform(tsr); _chart.Ptr().Render(gfx); gfx.PopTransform(); @@ -128,12 +122,12 @@ int OnStart() { return (INIT_SUCCEEDED); } - #else - +/** + * Implements OnInit(). + */ int OnInit() { // Nothing to test in non-MT5 environment. return (INIT_SUCCEEDED); } - -#endif \ No newline at end of file +#endif From 0f1aeec4a1c564c2b209615c5239eae1396253a9 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 11 Sep 2021 15:32:51 +0100 Subject: [PATCH 27/97] Bar: Adds missing Std include --- Bar.struct.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Bar.struct.h b/Bar.struct.h index a8c9bf7e3..95a7e6b17 100644 --- a/Bar.struct.h +++ b/Bar.struct.h @@ -39,6 +39,7 @@ class Serializer; #include "ISerializable.h" #include "Serializer.enum.h" #include "SerializerNode.enum.h" +#include "Std.h" /* Struct for storing OHLC values. */ struct BarOHLC From d7a02d234d734163f7a47ca329a753c60b8bc59c Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 11 Sep 2021 15:34:52 +0100 Subject: [PATCH 28/97] GHA: Adds 3DTest --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4bab1c69d..fca2896d8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -97,6 +97,7 @@ jobs: strategy: matrix: test: + - 3DTest - CollectionTest - ConfigTest - ConvertTest From ef21d9a8c91bf96dd6c5c02e6916982ea0a1caf1 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 14:54:43 +0100 Subject: [PATCH 29/97] Task: Moves Task to Task/ directory --- Action.struct.h | 2 +- Condition.struct.h | 2 +- EA.mqh | 2 +- EA.struct.h | 2 +- Strategy.mqh | 2 +- Strategy.struct.h | 2 +- Task.enum.h => Task/Task.enum.h | 0 Task.mqh => Task/Task.h | 8 ++++---- Task.struct.h => Task/Task.struct.h | 4 ++-- tests/TaskTest.mq4 => Task/tests/Task.test.mq4 | 2 +- tests/TaskTest.mq5 => Task/tests/Task.test.mq5 | 12 ++++++------ tests/CompileTest.mq5 | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) rename Task.enum.h => Task/Task.enum.h (100%) rename Task.mqh => Task/Task.h (98%) rename Task.struct.h => Task/Task.struct.h (98%) rename tests/TaskTest.mq4 => Task/tests/Task.test.mq4 (97%) rename tests/TaskTest.mq5 => Task/tests/Task.test.mq5 (95%) diff --git a/Action.struct.h b/Action.struct.h index 1f5481f14..5d9d1d962 100644 --- a/Action.struct.h +++ b/Action.struct.h @@ -40,7 +40,7 @@ #include "Order.enum.h" #include "Serializer.mqh" #include "Strategy.enum.h" -#include "Task.enum.h" +#include "Task/Task.enum.h" #include "Trade.enum.h" /* Entry for Action class. */ diff --git a/Condition.struct.h b/Condition.struct.h index 6e3376812..8a09c7160 100644 --- a/Condition.struct.h +++ b/Condition.struct.h @@ -38,7 +38,7 @@ //#include "Market.enum.h" #include "Order.enum.h" #include "Strategy.enum.h" -#include "Task.enum.h" +#include "Task/Task.enum.h" #include "Trade.enum.h" struct ConditionEntry { diff --git a/EA.mqh b/EA.mqh index dc69164c8..aaf1118c8 100644 --- a/EA.mqh +++ b/EA.mqh @@ -46,7 +46,7 @@ #include "SerializerSqlite.mqh" #include "Strategy.mqh" #include "SummaryReport.mqh" -#include "Task.mqh" +#include "Task/Task.h" #include "Terminal.mqh" #include "Trade.mqh" diff --git a/EA.struct.h b/EA.struct.h index aa36c2e5e..115329e19 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -32,7 +32,7 @@ // Includes. #include "DateTime.mqh" -#include "Task.struct.h" +#include "Task/Task.struct.h" /* Defines EA config parameters. */ struct EAParams { diff --git a/Strategy.mqh b/Strategy.mqh index 84af95675..3823f986f 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -36,7 +36,7 @@ class Trade; #include "Strategy.enum.h" #include "Strategy.struct.h" #include "String.mqh" -#include "Task.mqh" +#include "Task/Task.h" #include "Trade.mqh" // Defines. diff --git a/Strategy.struct.h b/Strategy.struct.h index 11c55f85f..2bd46ee92 100644 --- a/Strategy.struct.h +++ b/Strategy.struct.h @@ -34,7 +34,7 @@ #include "Serializer.mqh" #include "Strategy.enum.h" #include "Strategy.struct.pricestop.h" -#include "Task.struct.h" +#include "Task/Task.struct.h" // Forward class declaration. class Strategy; diff --git a/Task.enum.h b/Task/Task.enum.h similarity index 100% rename from Task.enum.h rename to Task/Task.enum.h diff --git a/Task.mqh b/Task/Task.h similarity index 98% rename from Task.mqh rename to Task/Task.h index 2db50c5e4..96152ec9a 100644 --- a/Task.mqh +++ b/Task/Task.h @@ -30,10 +30,10 @@ #define TASK_MQH // Includes. -#include "Action.mqh" -#include "Condition.mqh" -#include "DictStruct.mqh" -#include "Refs.mqh" +#include "../Action.mqh" +#include "../Condition.mqh" +#include "../DictStruct.mqh" +#include "../Refs.mqh" #include "Task.enum.h" #include "Task.struct.h" diff --git a/Task.struct.h b/Task/Task.struct.h similarity index 98% rename from Task.struct.h rename to Task/Task.struct.h index d1b7487ce..e9a4e977d 100644 --- a/Task.struct.h +++ b/Task/Task.struct.h @@ -31,8 +31,8 @@ #endif // Includes. -#include "Action.struct.h" -#include "Condition.struct.h" +#include "../Action.struct.h" +#include "../Condition.struct.h" #include "Task.enum.h" struct TaskEntry { diff --git a/tests/TaskTest.mq4 b/Task/tests/Task.test.mq4 similarity index 97% rename from tests/TaskTest.mq4 rename to Task/tests/Task.test.mq4 index 9dd81f28c..3ab46d4b9 100644 --- a/tests/TaskTest.mq4 +++ b/Task/tests/Task.test.mq4 @@ -25,4 +25,4 @@ */ // Includes. -#include "TaskTest.mq5" +#include "Task.test.mq5" diff --git a/tests/TaskTest.mq5 b/Task/tests/Task.test.mq5 similarity index 95% rename from tests/TaskTest.mq5 rename to Task/tests/Task.test.mq5 index 67ebb58d3..34652fedc 100644 --- a/tests/TaskTest.mq5 +++ b/Task/tests/Task.test.mq5 @@ -28,12 +28,12 @@ struct DataParamEntry; // Includes. -#include "../Action.mqh" -#include "../Chart.mqh" -#include "../DictObject.mqh" -#include "../EA.mqh" -#include "../Task.mqh" -#include "../Test.mqh" +#include "../../Action.mqh" +#include "../../Chart.mqh" +#include "../../DictObject.mqh" +#include "../../EA.mqh" +#include "../Task.h" +#include "../../Test.mqh" // Global variables. Chart *chart; diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index f9baa3e85..94171d422 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -99,7 +99,7 @@ #include "../String.mqh" #include "../SummaryReport.mqh" #include "../SymbolInfo.mqh" -#include "../Task.mqh" +#include "../Task/Task.h" #include "../Terminal.mqh" // #include "../Tester.mqh" // @removeme #include "../Storage/ValueStorage.h" From 9ad467e0efd839b835e710c40d5ba8e7ea81110e Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 15:07:17 +0100 Subject: [PATCH 30/97] Renames Condition to TaskCondition --- .github/workflows/test.yml | 2 - Action.mqh | 2 +- Chart.mqh | 2 +- Condition.struct.h | 111 ------------------ EA.mqh | 2 +- Market.mqh | 2 +- Task/Task.h | 4 +- Task/Task.struct.h | 22 ++-- Condition.enum.h => Task/TaskCondition.enum.h | 8 +- Condition.mqh => Task/TaskCondition.h | 60 +++++----- Task/TaskCondition.struct.h | 111 ++++++++++++++++++ Task/tests/Task.test.mq5 | 2 +- .../tests/TaskCondition.test.mq4 | 4 +- .../tests/TaskCondition.test.mq5 | 36 +++--- Trade.mqh | 2 +- tests/CompileTest.mq5 | 2 +- 16 files changed, 185 insertions(+), 187 deletions(-) delete mode 100644 Condition.struct.h rename Condition.enum.h => Task/TaskCondition.enum.h (98%) rename Condition.mqh => Task/TaskCondition.h (84%) create mode 100644 Task/TaskCondition.struct.h rename tests/ConditionTest.mq4 => Task/tests/TaskCondition.test.mq4 (92%) rename tests/ConditionTest.mq5 => Task/tests/TaskCondition.test.mq5 (77%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18c954e3f..d8b156bbd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,6 @@ jobs: - BufferTest - ChartTest - CompileIndicatorsTest - - ConditionTest - DatabaseTest - DrawIndicatorTest - EATest @@ -76,7 +75,6 @@ jobs: - StrategyTest-RSI - SymbolInfoTest - SummaryReportTest - - TaskTest - TickerTest - TradeTest steps: diff --git a/Action.mqh b/Action.mqh index 85f9a3a9b..2885da24c 100644 --- a/Action.mqh +++ b/Action.mqh @@ -35,8 +35,8 @@ class Action; // Includes. #include "Action.enum.h" #include "Action.struct.h" -#include "Condition.enum.h" #include "EA.mqh" +#include "Task/TaskCondition.enum.h" /** * Action class. diff --git a/Chart.mqh b/Chart.mqh index a568d8ae5..6a98e0644 100644 --- a/Chart.mqh +++ b/Chart.mqh @@ -42,10 +42,10 @@ class Market; #include "Chart.enum.h" #include "Chart.struct.h" #include "Chart.struct.serialize.h" -#include "Condition.enum.h" #include "Convert.mqh" #include "Market.mqh" #include "Serializer.mqh" +#include "Task/TaskCondition.enum.h" #ifndef __MQL4__ // Defines structs (for MQL4 backward compatibility). diff --git a/Condition.struct.h b/Condition.struct.h deleted file mode 100644 index 8a09c7160..000000000 --- a/Condition.struct.h +++ /dev/null @@ -1,111 +0,0 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2021, EA31337 Ltd | -//| https://github.com/EA31337 | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Includes Condition's structs. - */ - -#ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once -#endif - -// Includes. -#include "Account.enum.h" -#include "Chart.enum.h" -#include "DateTime.enum.h" -#include "EA.enum.h" -#include "Indicator.enum.h" -//#include "Market.enum.h" -#include "Order.enum.h" -#include "Strategy.enum.h" -#include "Task/Task.enum.h" -#include "Trade.enum.h" - -struct ConditionEntry { - unsigned char flags; // Condition flags. - datetime last_check; // Time of the latest check. - datetime last_success; // Time of the last success. - int frequency; // How often to check. - long cond_id; // Condition ID. - short tries; // Number of successful tries left. - void *obj; // Reference to associated object. - ENUM_CONDITION_STATEMENT next_statement; // Statement type of the next condition. - ENUM_CONDITION_TYPE type; // Condition type. - DataParamEntry args[]; // Condition arguments. - // Constructors. - void ConditionEntry() : type(FINAL_CONDITION_TYPE_ENTRY), cond_id(WRONG_VALUE) { Init(); } - void ConditionEntry(long _cond_id, ENUM_CONDITION_TYPE _type) : type(_type), cond_id(_cond_id) { Init(); } - void ConditionEntry(ConditionEntry &_ce) { this = _ce; } - void ConditionEntry(ENUM_ACCOUNT_CONDITION _cond_id) : type(COND_TYPE_ACCOUNT), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_CHART_CONDITION _cond_id) : type(COND_TYPE_CHART), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_DATETIME_CONDITION _cond_id) : type(COND_TYPE_DATETIME), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_EA_CONDITION _cond_id) : type(COND_TYPE_EA), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_INDICATOR_CONDITION _cond_id) : type(COND_TYPE_INDICATOR), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_MARKET_CONDITION _cond_id) : type(COND_TYPE_MARKET), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_ORDER_CONDITION _cond_id) : type(COND_TYPE_ORDER), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_STRATEGY_CONDITION _cond_id) : type(COND_TYPE_STRATEGY), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_TASK_CONDITION _cond_id) : type(COND_TYPE_TASK), cond_id(_cond_id) { Init(); } - void ConditionEntry(ENUM_TRADE_CONDITION _cond_id) : type(COND_TYPE_TRADE), cond_id(_cond_id) { Init(); } - // Deconstructor. - void ~ConditionEntry() { - // Object::Delete(obj); - } - // Flag methods. - bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } - void AddFlags(unsigned char _flags) { flags |= _flags; } - void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } - void SetFlag(ENUM_CONDITION_ENTRY_FLAGS _flag, bool _value) { - if (_value) - AddFlags(_flag); - else - RemoveFlags(_flag); - } - void SetFlags(unsigned char _flags) { flags = _flags; } - // State methods. - bool IsActive() { return HasFlag(COND_ENTRY_FLAG_IS_ACTIVE); } - bool IsExpired() { return HasFlag(COND_ENTRY_FLAG_IS_EXPIRED); } - bool IsReady() { return HasFlag(COND_ENTRY_FLAG_IS_READY); } - bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); } - bool IsValid() { return !IsInvalid(); } - // Getters. - long GetId() { return cond_id; } - ENUM_CONDITION_TYPE GetType() { return type; } - // Setters. - void AddArg(MqlParam &_arg) { - // @todo: Add another value to args[]. - } - void Init() { - flags = COND_ENTRY_FLAG_NONE; - frequency = 60; - SetFlag(COND_ENTRY_FLAG_IS_ACTIVE, cond_id != WRONG_VALUE); - SetFlag(COND_ENTRY_FLAG_IS_INVALID, cond_id == WRONG_VALUE); - last_check = last_success = 0; - next_statement = COND_AND; - tries = 1; - } - void SetArgs(MqlParam &_args[]) { - // @todo: for(). - } - void SetObject(void *_obj) { obj = _obj; } - void SetTries(short _count) { tries = _count; } -}; diff --git a/EA.mqh b/EA.mqh index aaf1118c8..d94f61ea5 100644 --- a/EA.mqh +++ b/EA.mqh @@ -32,7 +32,6 @@ // Includes. #include "Action.enum.h" #include "Chart.mqh" -#include "Condition.enum.h" #include "Data.struct.h" #include "Dict.mqh" #include "DictObject.mqh" @@ -47,6 +46,7 @@ #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/Task.h" +#include "Task/TaskCondition.enum.h" #include "Terminal.mqh" #include "Trade.mqh" diff --git a/Market.mqh b/Market.mqh index b9a2bf9bc..c5945335b 100644 --- a/Market.mqh +++ b/Market.mqh @@ -29,12 +29,12 @@ class Market; class SymbolInfo; // Includes. -#include "Condition.enum.h" #include "Market.struct.h" #include "Math.h" #include "Order.mqh" #include "Serializer.mqh" #include "SymbolInfo.mqh" +#include "Task/TaskCondition.enum.h" // Structs. // Market info. diff --git a/Task/Task.h b/Task/Task.h index 96152ec9a..2c41e2ead 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -31,9 +31,9 @@ // Includes. #include "../Action.mqh" -#include "../Condition.mqh" #include "../DictStruct.mqh" #include "../Refs.mqh" +#include "../Task/TaskCondition.h" #include "Task.enum.h" #include "Task.struct.h" @@ -98,7 +98,7 @@ class Task { static bool Process(TaskEntry &_entry) { bool _result = false; if (_entry.IsActive()) { - if (Condition::Test(_entry.GetCondition())) { + if (TaskCondition::Test(_entry.GetCondition())) { ActionEntry _action = _entry.GetAction(); Action::Execute(_action); if (_action.IsDone()) { diff --git a/Task/Task.struct.h b/Task/Task.struct.h index e9a4e977d..57b5d856c 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -32,20 +32,20 @@ // Includes. #include "../Action.struct.h" -#include "../Condition.struct.h" #include "Task.enum.h" +#include "TaskCondition.struct.h" struct TaskEntry { - ActionEntry action; // Action of the task. - ConditionEntry cond; // Condition of the task. - datetime expires; // Time of expiration. - datetime last_process; // Time of the last process. - datetime last_success; // Time of the last success. - unsigned char flags; // Action flags. + ActionEntry action; // Action of the task. + TaskConditionEntry cond; // TaskCondition of the task. + datetime expires; // Time of expiration. + datetime last_process; // Time of the last process. + datetime last_success; // Time of the last success. + unsigned char flags; // Action flags. // Constructors. void TaskEntry() { Init(); } - void TaskEntry(ActionEntry &_action, ConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } - void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_CONDITION_TYPE _ctype) + void TaskEntry(ActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } + void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_TASK_CONDITION_TYPE _ctype) : action(_aid, _atype), cond(_cid, _ctype) { Init(); } @@ -80,9 +80,9 @@ struct TaskEntry { long GetActionId() { return action.GetId(); } long GetConditionId() { return cond.GetId(); } ActionEntry GetAction() { return action; } - ConditionEntry GetCondition() { return cond; } + TaskConditionEntry GetCondition() { return cond; } ENUM_ACTION_TYPE GetActionType() { return action.GetType(); } - ENUM_CONDITION_TYPE GetConditionType() { return cond.GetType(); } + ENUM_TASK_CONDITION_TYPE GetConditionType() { return cond.GetType(); } // Setters. void SetActionObject(void *_obj) { action.SetObject(_obj); } void SetConditionObject(void *_obj) { cond.SetObject(_obj); } diff --git a/Condition.enum.h b/Task/TaskCondition.enum.h similarity index 98% rename from Condition.enum.h rename to Task/TaskCondition.enum.h index 3f7a8e9a4..25faf93a4 100644 --- a/Condition.enum.h +++ b/Task/TaskCondition.enum.h @@ -21,7 +21,7 @@ /** * @file - * Includes Condition's enums. + * Includes TaskCondition's enums. */ #ifndef __MQL__ @@ -85,7 +85,7 @@ enum ENUM_MARKET_EVENT { #endif /* Defines condition entry flags. */ -enum ENUM_CONDITION_ENTRY_FLAGS { +enum ENUM_TASK_CONDITION_ENTRY_FLAGS { COND_ENTRY_FLAG_NONE = 0, COND_ENTRY_FLAG_IS_ACTIVE = 1, COND_ENTRY_FLAG_IS_EXPIRED = 2, @@ -94,7 +94,7 @@ enum ENUM_CONDITION_ENTRY_FLAGS { }; /* Defines condition statements (operators). */ -enum ENUM_CONDITION_STATEMENT { +enum ENUM_TASK_CONDITION_STATEMENT { COND_AND = 1, // Use AND statement. COND_OR, // Use OR statement. COND_SEQ, // Use sequential checks. @@ -102,7 +102,7 @@ enum ENUM_CONDITION_STATEMENT { }; /* Defines condition types. */ -enum ENUM_CONDITION_TYPE { +enum ENUM_TASK_CONDITION_TYPE { COND_TYPE_ACCOUNT = 1, // Account condition. COND_TYPE_ACTION, // Action condition. COND_TYPE_CHART, // Chart condition. diff --git a/Condition.mqh b/Task/TaskCondition.h similarity index 84% rename from Condition.mqh rename to Task/TaskCondition.h index 27183866b..194a5920d 100644 --- a/Condition.mqh +++ b/Task/TaskCondition.h @@ -26,28 +26,28 @@ */ // Prevents processing this includes file for the second time. -#ifndef CONDITION_MQH -#define CONDITION_MQH +#ifndef TASK_CONDITION_MQH +#define TASK_CONDITION_MQH // Includes. -#include "Account.mqh" -#include "Chart.mqh" -#include "DateTime.mqh" -#include "DictStruct.mqh" -#include "EA.mqh" -#include "Indicator.mqh" -#include "Market.mqh" -#include "Object.mqh" -#include "Order.mqh" +#include "../Account.mqh" +#include "../Chart.mqh" +#include "../DateTime.mqh" +#include "../DictStruct.mqh" +#include "../EA.mqh" +#include "../Indicator.mqh" +#include "../Market.mqh" +#include "../Object.mqh" +#include "../Order.mqh" // Includes class enum and structs. -#include "Condition.enum.h" -#include "Condition.struct.h" +#include "TaskCondition.enum.h" +#include "TaskCondition.struct.h" /** - * Condition class. + * TaskCondition class. */ -class Condition { +class TaskCondition { public: protected: // Class variables. @@ -55,31 +55,31 @@ class Condition { public: // Class variables. - DictStruct conds; + DictStruct conds; /* Special methods */ /** * Class constructor. */ - Condition() {} - Condition(ConditionEntry &_entry) { conds.Push(_entry); } - Condition(long _cond_id, ENUM_CONDITION_TYPE _type) { - ConditionEntry _entry(_cond_id, _type); + TaskCondition() {} + TaskCondition(TaskConditionEntry &_entry) { conds.Push(_entry); } + TaskCondition(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) { + TaskConditionEntry _entry(_cond_id, _type); conds.Push(_entry); } template - Condition(T _cond_id, void *_obj = NULL) { - ConditionEntry _entry(_cond_id); + TaskCondition(T _cond_id, void *_obj = NULL) { + TaskConditionEntry _entry(_cond_id); if (_obj != NULL) { _entry.SetObject(_obj); } conds.Push(_entry); } template - Condition(T _cond_id, MqlParam &_args[], void *_obj = NULL) { + TaskCondition(T _cond_id, MqlParam &_args[], void *_obj = NULL) { Init(); - ConditionEntry _entry(_cond_id); + TaskConditionEntry _entry(_cond_id); _entry.SetArgs(_args); if (_obj != NULL) { _entry.SetObject(_obj); @@ -90,7 +90,7 @@ class Condition { /** * Class copy constructor. */ - Condition(Condition &_cond) { conds = _cond.GetConditions(); } + TaskCondition(TaskCondition &_cond) { conds = _cond.GetConditions(); } /* Main methods */ @@ -99,9 +99,9 @@ class Condition { */ bool Test() { bool _result = false, _prev_result = true; - for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { bool _curr_result = false; - ConditionEntry _entry = iter.Value(); + TaskConditionEntry _entry = iter.Value(); if (!_entry.IsValid()) { // Ignore invalid entries. continue; @@ -130,7 +130,7 @@ class Condition { /** * Test specific condition. */ - static bool Test(ConditionEntry &_entry) { + static bool Test(TaskConditionEntry &_entry) { bool _result = false; switch (_entry.type) { case COND_TYPE_ACCOUNT: @@ -260,8 +260,8 @@ class Condition { /** * Returns conditions. */ - DictStruct *GetConditions() { return &conds; } + DictStruct *GetConditions() { return &conds; } /* Setters */ }; -#endif // CONDITION_MQH +#endif // TASK_CONDITION_MQH diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h new file mode 100644 index 000000000..97b10383e --- /dev/null +++ b/Task/TaskCondition.struct.h @@ -0,0 +1,111 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Includes Condition's structs. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Account.enum.h" +#include "../Chart.enum.h" +#include "../DateTime.enum.h" +#include "../EA.enum.h" +#include "../Indicator.enum.h" +//#include "Market.enum.h" +#include "../Order.enum.h" +#include "../Strategy.enum.h" +#include "../Trade.enum.h" +#include "Task.enum.h" + +struct TaskConditionEntry { + unsigned char flags; // Condition flags. + datetime last_check; // Time of the latest check. + datetime last_success; // Time of the last success. + int frequency; // How often to check. + long cond_id; // Condition ID. + short tries; // Number of successful tries left. + void *obj; // Reference to associated object. + ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. + ENUM_TASK_CONDITION_TYPE type; // Task's condition type. + DataParamEntry args[]; // Task's condition arguments. + // Constructors. + void TaskConditionEntry() : type(FINAL_CONDITION_TYPE_ENTRY), cond_id(WRONG_VALUE) { Init(); } + void TaskConditionEntry(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) : type(_type), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(TaskConditionEntry &_ce) { this = _ce; } + void TaskConditionEntry(ENUM_ACCOUNT_CONDITION _cond_id) : type(COND_TYPE_ACCOUNT), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_CHART_CONDITION _cond_id) : type(COND_TYPE_CHART), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_DATETIME_CONDITION _cond_id) : type(COND_TYPE_DATETIME), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_EA_CONDITION _cond_id) : type(COND_TYPE_EA), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_INDICATOR_CONDITION _cond_id) : type(COND_TYPE_INDICATOR), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_MARKET_CONDITION _cond_id) : type(COND_TYPE_MARKET), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_ORDER_CONDITION _cond_id) : type(COND_TYPE_ORDER), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_STRATEGY_CONDITION _cond_id) : type(COND_TYPE_STRATEGY), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_TASK_CONDITION _cond_id) : type(COND_TYPE_TASK), cond_id(_cond_id) { Init(); } + void TaskConditionEntry(ENUM_TRADE_CONDITION _cond_id) : type(COND_TYPE_TRADE), cond_id(_cond_id) { Init(); } + // Deconstructor. + void ~TaskConditionEntry() { + // Object::Delete(obj); + } + // Flag methods. + bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } + void AddFlags(unsigned char _flags) { flags |= _flags; } + void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void SetFlag(ENUM_TASK_CONDITION_ENTRY_FLAGS _flag, bool _value) { + if (_value) + AddFlags(_flag); + else + RemoveFlags(_flag); + } + void SetFlags(unsigned char _flags) { flags = _flags; } + // State methods. + bool IsActive() { return HasFlag(COND_ENTRY_FLAG_IS_ACTIVE); } + bool IsExpired() { return HasFlag(COND_ENTRY_FLAG_IS_EXPIRED); } + bool IsReady() { return HasFlag(COND_ENTRY_FLAG_IS_READY); } + bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); } + bool IsValid() { return !IsInvalid(); } + // Getters. + long GetId() { return cond_id; } + ENUM_TASK_CONDITION_TYPE GetType() { return type; } + // Setters. + void AddArg(MqlParam &_arg) { + // @todo: Add another value to args[]. + } + void Init() { + flags = COND_ENTRY_FLAG_NONE; + frequency = 60; + SetFlag(COND_ENTRY_FLAG_IS_ACTIVE, cond_id != WRONG_VALUE); + SetFlag(COND_ENTRY_FLAG_IS_INVALID, cond_id == WRONG_VALUE); + last_check = last_success = 0; + next_statement = COND_AND; + tries = 1; + } + void SetArgs(MqlParam &_args[]) { + // @todo: for(). + } + void SetObject(void *_obj) { obj = _obj; } + void SetTries(short _count) { tries = _count; } +}; diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 34652fedc..f84783996 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -32,8 +32,8 @@ struct DataParamEntry; #include "../../Chart.mqh" #include "../../DictObject.mqh" #include "../../EA.mqh" -#include "../Task.h" #include "../../Test.mqh" +#include "../Task.h" // Global variables. Chart *chart; diff --git a/tests/ConditionTest.mq4 b/Task/tests/TaskCondition.test.mq4 similarity index 92% rename from tests/ConditionTest.mq4 rename to Task/tests/TaskCondition.test.mq4 index 89bff6caa..961feb86a 100644 --- a/tests/ConditionTest.mq4 +++ b/Task/tests/TaskCondition.test.mq4 @@ -21,8 +21,8 @@ /** * @file - * Test functionality of Condition class. + * Test functionality of TaskCondition class. */ // Includes. -#include "ConditionTest.mq5" +#include "TaskCondition.test.mq5" diff --git a/tests/ConditionTest.mq5 b/Task/tests/TaskCondition.test.mq5 similarity index 77% rename from tests/ConditionTest.mq5 rename to Task/tests/TaskCondition.test.mq5 index bb92cf89b..fd2d006f9 100644 --- a/tests/ConditionTest.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -21,21 +21,21 @@ /** * @file - * Test functionality of Condition class. + * Test functionality of TaskCondition class. */ // Forward declaration. struct DataParamEntry; // Includes. -#include "../Condition.mqh" -#include "../DictObject.mqh" -#include "../Indicators/Indi_Demo.mqh" -#include "../Test.mqh" +#include "../../DictObject.mqh" +#include "../../Indicators/Indi_Demo.mqh" +#include "../../Test.mqh" +#include "../TaskCondition.h" // Global variables. Chart *chart; -DictObject conds; +DictObject conds; int bar_processed; /** @@ -78,7 +78,7 @@ void OnDeinit(const int reason) { delete chart; } bool TestAccountConditions() { bool _result = true; Account *_acc = new Account(); - Condition *_cond = new Condition(ACCOUNT_COND_BAL_IN_LOSS); + TaskCondition *_cond = new TaskCondition(ACCOUNT_COND_BAL_IN_LOSS); assertTrueOrReturnFalse(_cond.Test() == _acc.CheckCondition(ACCOUNT_COND_BAL_IN_LOSS), "Wrong condition: ACCOUNT_COND_BAL_IN_LOSS!"); delete _cond; @@ -92,7 +92,7 @@ bool TestAccountConditions() { bool TestChartConditions() { bool _result = true; Chart *_chart = new Chart(); - Condition *_cond = new Condition(CHART_COND_ASK_BAR_PEAK, _chart); + TaskCondition *_cond = new TaskCondition(CHART_COND_ASK_BAR_PEAK, _chart); assertTrueOrReturnFalse(_cond.Test() == _chart.CheckCondition(CHART_COND_ASK_BAR_PEAK), "Wrong condition: CHART_COND_ASK_BAR_PEAK!"); delete _cond; @@ -106,11 +106,11 @@ bool TestChartConditions() { bool TestDateTimeConditions() { bool _result = true; DateTime *_dt = new DateTime(); - Condition *_cond1 = new Condition(DATETIME_COND_NEW_HOUR, _dt); + TaskCondition *_cond1 = new TaskCondition(DATETIME_COND_NEW_HOUR, _dt); assertTrueOrReturnFalse(_cond1.Test() == _dt.CheckCondition(DATETIME_COND_NEW_HOUR), "Wrong condition: DATETIME_COND_NEW_HOUR (dynamic)!"); delete _cond1; - Condition *_cond2 = new Condition(DATETIME_COND_NEW_HOUR); + TaskCondition *_cond2 = new TaskCondition(DATETIME_COND_NEW_HOUR); assertTrueOrReturnFalse(_cond2.Test() == DateTime::CheckCondition(DATETIME_COND_NEW_HOUR), "Wrong condition: DATETIME_COND_NEW_HOUR (static)!"); delete _cond2; @@ -126,22 +126,22 @@ bool TestIndicatorConditions() { Indi_Demo *_demo = new Indi_Demo(); /* @fixme assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_IS_MAX, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MAX), + (new TaskCondition(INDI_COND_ENTRY_IS_MAX, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MAX), "Wrong condition: INDI_COND_ENTRY_IS_MAX!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_IS_MIN, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MIN), + (new TaskCondition(INDI_COND_ENTRY_IS_MIN, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MIN), "Wrong condition: INDI_COND_ENTRY_IS_MIN!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_GT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_AVG), + (new TaskCondition(INDI_COND_ENTRY_GT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_AVG), "Wrong condition: INDI_COND_ENTRY_GT_AVG!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_GT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_MED), + (new TaskCondition(INDI_COND_ENTRY_GT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_MED), "Wrong condition: INDI_COND_ENTRY_GT_MED!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_LT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_AVG), + (new TaskCondition(INDI_COND_ENTRY_LT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_AVG), "Wrong condition: INDI_COND_ENTRY_LT_AVG!"); assertTrueOrReturnFalse( - (new Condition(INDI_COND_ENTRY_LT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_MED), + (new TaskCondition(INDI_COND_ENTRY_LT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_MED), "Wrong condition: INDI_COND_ENTRY_LT_MED!"); */ delete _demo; @@ -154,7 +154,7 @@ bool TestIndicatorConditions() { bool TestMarketConditions() { bool _result = true; Market *_market = new Market(); - Condition *_cond = new Condition(MARKET_COND_IN_PEAK_HOURS, _market); + TaskCondition *_cond = new TaskCondition(MARKET_COND_IN_PEAK_HOURS, _market); assertTrueOrReturnFalse(_cond.Test() == _market.CheckCondition(MARKET_COND_IN_PEAK_HOURS), "Wrong condition: MARKET_COND_IN_PEAK_HOURS!"); delete _cond; @@ -186,7 +186,7 @@ bool TestOrderConditions() { bool TestTradeConditions() { bool _result = true; Trade *_trade = new Trade(); - Condition *_cond = new Condition(TRADE_COND_ALLOWED_NOT, _trade); + TaskCondition *_cond = new TaskCondition(TRADE_COND_ALLOWED_NOT, _trade); assertTrueOrReturnFalse(_cond.Test() == _trade.CheckCondition(TRADE_COND_ALLOWED_NOT), "Wrong condition: TRADE_COND_ALLOWED_NOT!"); delete _cond; diff --git a/Trade.mqh b/Trade.mqh index c19a1db9e..78877e5e7 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -33,13 +33,13 @@ class Trade; #include "Account.mqh" #include "Action.enum.h" #include "Chart.mqh" -#include "Condition.enum.h" #include "Convert.mqh" #include "DictStruct.mqh" #include "Math.h" #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" +#include "Task/TaskCondition.enum.h" #include "Trade.enum.h" #include "Trade.struct.h" diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 94171d422..aa40a93cb 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -33,7 +33,6 @@ #include "../BufferStruct.mqh" #include "../Chart.mqh" #include "../Collection.mqh" -#include "../Condition.mqh" #include "../Config.mqh" #include "../Convert.mqh" #include "../Database.mqh" @@ -56,6 +55,7 @@ #include "../Log.mqh" #include "../MD5.mqh" #include "../Storage/IValueStorage.h" +#include "../Task/TaskCondition.h" //#include "../MQL4.mqh" // @removeme //#include "../MQL5.mqh" // @removeme #include "../Mail.mqh" From 54d8c0abc1abaab607df942fd54570a86e907c4f Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 15:45:18 +0100 Subject: [PATCH 31/97] Renames Action to TaskAction --- .github/workflows/test.yml | 1 - EA.mqh | 2 +- EA.struct.h | 2 +- Indicators/Indi_Drawer.mqh | 6 +- Order.mqh | 2 +- Task/Task.enum.h | 4 +- Task/Task.h | 8 +-- Task/Task.struct.h | 10 +-- Action.enum.h => Task/TaskAction.enum.h | 6 +- Action.mqh => Task/TaskAction.h | 62 +++++++++---------- Action.struct.h => Task/TaskAction.struct.h | 58 ++++++++--------- Task/TaskCondition.enum.h | 4 +- Task/tests/Task.test.mq5 | 3 +- .../tests/TaskAction.test.mq4 | 4 +- .../tests/TaskAction.test.mq5 | 16 ++--- Trade.mqh | 4 +- tests/CompileTest.mq5 | 2 +- 17 files changed, 97 insertions(+), 97 deletions(-) rename Action.enum.h => Task/TaskAction.enum.h (95%) rename Action.mqh => Task/TaskAction.h (84%) rename Action.struct.h => Task/TaskAction.struct.h (67%) rename tests/ActionTest.mq4 => Task/tests/TaskAction.test.mq4 (93%) rename tests/ActionTest.mq5 => Task/tests/TaskAction.test.mq5 (92%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d8b156bbd..297e43562 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,7 +54,6 @@ jobs: matrix: test: - AccountTest - - ActionTest - BufferStructTest - BufferTest - ChartTest diff --git a/EA.mqh b/EA.mqh index d94f61ea5..54aef90b3 100644 --- a/EA.mqh +++ b/EA.mqh @@ -30,7 +30,6 @@ #define EA_MQH // Includes. -#include "Action.enum.h" #include "Chart.mqh" #include "Data.struct.h" #include "Dict.mqh" @@ -46,6 +45,7 @@ #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/Task.h" +#include "Task/TaskAction.enum.h" #include "Task/TaskCondition.enum.h" #include "Terminal.mqh" #include "Trade.mqh" diff --git a/EA.struct.h b/EA.struct.h index 115329e19..a750d2e11 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -222,7 +222,7 @@ struct EAProcessResult { /* Defines EA state variables. */ struct EAState { - unsigned short flags; // Action flags. + unsigned short flags; // TaskAction flags. unsigned int new_periods; // Started periods. DateTime last_updated; // Last updated. // Constructor. diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d6f81854b..d5878da2e 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -24,10 +24,10 @@ struct IndicatorParams; // Includes. -#include "../Action.mqh" #include "../DictStruct.mqh" #include "../Indicator.mqh" #include "../Redis.mqh" +#include "../Task/TaskAction.h" #include "Indi_Drawer.struct.h" #include "Indi_Price.mqh" @@ -114,7 +114,7 @@ class Indi_Drawer : public Indicator { virtual void OnTick() { Indicator::OnTick(); - ActionEntry action(INDI_ACTION_SET_VALUE); + TaskActionEntry action(INDI_ACTION_SET_VALUE); ArrayResize(action.args, 3); action.args[0].type = TYPE_LONG; action.args[0].integer_value = GetBarTime(); @@ -141,7 +141,7 @@ class Indi_Drawer : public Indicator { Print("Got: ", message.Message); #endif if (message.Command == "message" && message.Channel == "INDICATOR_DRAW") { - ActionEntry action_entry; + TaskActionEntry action_entry; SerializerConverter::FromString(message.Message).ToObject(action_entry); ExecuteAction((ENUM_INDICATOR_ACTION)action_entry.action_id, action_entry.args); #ifdef __debug__ diff --git a/Order.mqh b/Order.mqh index 7cbba164b..38ad8d33f 100644 --- a/Order.mqh +++ b/Order.mqh @@ -30,7 +30,6 @@ #define ORDER_MQH // Includes. -#include "Action.enum.h" #include "Convert.mqh" #include "Data.define.h" #include "Data.struct.h" @@ -43,6 +42,7 @@ #include "Std.h" #include "String.mqh" #include "SymbolInfo.mqh" +#include "Task/TaskAction.enum.h" /* Defines for backward compatibility. */ diff --git a/Task/Task.enum.h b/Task/Task.enum.h index 0fcbc5b48..66b180b1f 100644 --- a/Task/Task.enum.h +++ b/Task/Task.enum.h @@ -30,14 +30,14 @@ #pragma once #endif -/* Structure for task actions for Action class. */ +/* Structure for task actions for TaskAction class. */ enum ENUM_TASK_ACTION { TASK_ACTION_NONE = 0, // Does nothing. TASK_ACTION_PROCESS, // Process tasks. FINAL_TASK_ACTION_ENTRY }; -/* Structure for task conditions for Action class. */ +/* Structure for task conditions for TaskAction class. */ enum ENUM_TASK_CONDITION { TASK_COND_NONE = 0, // Empty condition. TASK_COND_IS_ACTIVE, // Is active. diff --git a/Task/Task.h b/Task/Task.h index 2c41e2ead..4c5863a32 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -30,12 +30,12 @@ #define TASK_MQH // Includes. -#include "../Action.mqh" #include "../DictStruct.mqh" #include "../Refs.mqh" -#include "../Task/TaskCondition.h" #include "Task.enum.h" #include "Task.struct.h" +#include "TaskAction.h" +#include "TaskCondition.h" class Task { protected: @@ -99,8 +99,8 @@ class Task { bool _result = false; if (_entry.IsActive()) { if (TaskCondition::Test(_entry.GetCondition())) { - ActionEntry _action = _entry.GetAction(); - Action::Execute(_action); + TaskActionEntry _action = _entry.GetAction(); + TaskAction::Execute(_action); if (_action.IsDone()) { _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, _action.IsDone()); _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, _action.IsFailed()); diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 57b5d856c..4c9b328d0 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -31,20 +31,20 @@ #endif // Includes. -#include "../Action.struct.h" #include "Task.enum.h" +#include "TaskAction.struct.h" #include "TaskCondition.struct.h" struct TaskEntry { - ActionEntry action; // Action of the task. + TaskActionEntry action; // TaskAction of the task. TaskConditionEntry cond; // TaskCondition of the task. datetime expires; // Time of expiration. datetime last_process; // Time of the last process. datetime last_success; // Time of the last success. - unsigned char flags; // Action flags. + unsigned char flags; // TaskAction flags. // Constructors. void TaskEntry() { Init(); } - void TaskEntry(ActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } + void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_TASK_CONDITION_TYPE _ctype) : action(_aid, _atype), cond(_cid, _ctype) { Init(); @@ -79,7 +79,7 @@ struct TaskEntry { // Getters. long GetActionId() { return action.GetId(); } long GetConditionId() { return cond.GetId(); } - ActionEntry GetAction() { return action; } + TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } ENUM_ACTION_TYPE GetActionType() { return action.GetType(); } ENUM_TASK_CONDITION_TYPE GetConditionType() { return cond.GetType(); } diff --git a/Action.enum.h b/Task/TaskAction.enum.h similarity index 95% rename from Action.enum.h rename to Task/TaskAction.enum.h index 551ae44f7..ed6a40cb6 100644 --- a/Action.enum.h +++ b/Task/TaskAction.enum.h @@ -21,7 +21,7 @@ /** * @file - * Includes Action's enums. + * Includes TaskAction's enums. */ #ifndef __MQL__ @@ -45,7 +45,7 @@ enum ENUM_ACTION_ENTRY_FLAGS { /* Defines action types. */ enum ENUM_ACTION_TYPE { ACTION_TYPE_NONE = 0, // None. - ACTION_TYPE_ACTION, // Action of action. + ACTION_TYPE_ACTION, // TaskAction of action. ACTION_TYPE_EA, // EA action. ACTION_TYPE_INDICATOR, // Order action. ACTION_TYPE_ORDER, // Order action. @@ -56,7 +56,7 @@ enum ENUM_ACTION_TYPE { FINAL_ACTION_TYPE_ENTRY }; -/* Defines action types for Action class. */ +/* Defines action types for TaskAction class. */ enum ENUM_ACTION_ACTION { ACTION_ACTION_NONE = 0, // Does nothing. ACTION_ACTION_DISABLE, // Disables action. diff --git a/Action.mqh b/Task/TaskAction.h similarity index 84% rename from Action.mqh rename to Task/TaskAction.h index 2885da24c..15650d050 100644 --- a/Action.mqh +++ b/Task/TaskAction.h @@ -30,18 +30,18 @@ #define ACTION_MQH // Forward class declaration. -class Action; +class TaskAction; // Includes. -#include "Action.enum.h" -#include "Action.struct.h" -#include "EA.mqh" -#include "Task/TaskCondition.enum.h" +#include "../EA.mqh" +#include "TaskAction.enum.h" +#include "TaskAction.struct.h" +#include "TaskCondition.enum.h" /** - * Action class. + * TaskAction class. */ -class Action { +class TaskAction { public: protected: // Class variables. @@ -49,30 +49,30 @@ class Action { public: // Class variables. - DictStruct actions; + DictStruct actions; /* Special methods */ /** * Class constructor. */ - Action() {} - Action(ActionEntry &_entry) { actions.Push(_entry); } - Action(long _action_id, ENUM_ACTION_TYPE _type) { - ActionEntry _entry(_action_id, _type); + TaskAction() {} + TaskAction(TaskActionEntry &_entry) { actions.Push(_entry); } + TaskAction(long _action_id, ENUM_ACTION_TYPE _type) { + TaskActionEntry _entry(_action_id, _type); actions.Push(_entry); } template - Action(T _action_id, void *_obj = NULL) { - ActionEntry _entry(_action_id); + TaskAction(T _action_id, void *_obj = NULL) { + TaskActionEntry _entry(_action_id); if (_obj != NULL) { _entry.SetObject(_obj); } actions.Push(_entry); } template - Action(T _action_id, MqlParam &_args[], void *_obj = NULL) { - ActionEntry _entry(_action_id); + TaskAction(T _action_id, MqlParam &_args[], void *_obj = NULL) { + TaskActionEntry _entry(_action_id); _entry.SetArgs(_args); if (_obj != NULL) { _entry.SetObject(_obj); @@ -83,7 +83,7 @@ class Action { /** * Class copy constructor. */ - Action(Action &_cond) { actions = _cond.GetActions(); } + TaskAction(TaskAction &_cond) { actions = _cond.GetActions(); } /* Main methods */ @@ -92,9 +92,9 @@ class Action { */ bool Execute() { bool _result = true, _executed = false; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { + for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { bool _curr_result = false; - ActionEntry _entry = iter.Value(); + TaskActionEntry _entry = iter.Value(); if (!_entry.IsValid()) { // Ignore invalid entries. continue; @@ -109,12 +109,12 @@ class Action { /** * Execute specific action. */ - static bool Execute(ActionEntry &_entry) { + static bool Execute(TaskActionEntry &_entry) { bool _result = false; switch (_entry.type) { case ACTION_TYPE_ACTION: if (Object::IsValid(_entry.obj)) { - _result = ((Action *)_entry.obj).ExecuteAction((ENUM_ACTION_ACTION)_entry.action_id, _entry.args); + _result = ((TaskAction *)_entry.obj).ExecuteAction((ENUM_ACTION_ACTION)_entry.action_id, _entry.args); } else { _result = false; _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); @@ -247,15 +247,15 @@ class Action { /** * Returns actions. */ - DictStruct *GetActions() { return &actions; } + DictStruct *GetActions() { return &actions; } /** * Count entry flags. */ unsigned int GetFlagCount(ENUM_ACTION_ENTRY_FLAGS _flag) { unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - ActionEntry _entry = iter.Value(); + for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { + TaskActionEntry _entry = iter.Value(); if (_entry.HasFlag(_flag)) { _counter++; } @@ -270,8 +270,8 @@ class Action { */ bool SetFlags(ENUM_ACTION_ENTRY_FLAGS _flag, bool _value = true) { unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - ActionEntry _entry = iter.Value(); + for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { + TaskActionEntry _entry = iter.Value(); switch (_value) { case false: if (_entry.HasFlag(_flag)) { @@ -296,7 +296,7 @@ class Action { * Checks for Task condition. * * @param ENUM_ACTION_CONDITION _cond - * Action condition. + * TaskAction condition. * @return * Returns true when the condition is met. */ @@ -318,20 +318,20 @@ class Action { // Is invalid. return IsInvalid(); default: - logger.Ptr().Error(StringFormat("Invalid Action condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + logger.Ptr().Error(StringFormat("Invalid TaskAction condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } bool CheckCondition(ENUM_ACTION_CONDITION _cond) { ARRAY(DataParamEntry, _args); - return Action::CheckCondition(_cond, _args); + return TaskAction::CheckCondition(_cond, _args); } /** * Execute action of action. * * @param ENUM_ACTION_ACTION _action - * Action of action to execute. + * TaskAction of action to execute. * @return * Returns true when the action has been executed successfully. */ @@ -364,7 +364,7 @@ class Action { } bool ExecuteAction(ENUM_ACTION_ACTION _action) { ARRAY(DataParamEntry, _args); - return Action::ExecuteAction(_action, _args); + return TaskAction::ExecuteAction(_action, _args); } /* Other methods */ diff --git a/Action.struct.h b/Task/TaskAction.struct.h similarity index 67% rename from Action.struct.h rename to Task/TaskAction.struct.h index 5d9d1d962..21434aa67 100644 --- a/Action.struct.h +++ b/Task/TaskAction.struct.h @@ -21,7 +21,7 @@ /** * @file - * Includes Action's structs. + * Includes TaskAction's structs. */ #ifndef __MQL__ @@ -30,41 +30,41 @@ #endif // Includes. -#include "Account.enum.h" -#include "Action.enum.h" -#include "Chart.enum.h" -#include "Data.struct.h" -#include "EA.enum.h" -#include "Indicator.enum.h" -//#include "Market.enum.h" -#include "Order.enum.h" -#include "Serializer.mqh" -#include "Strategy.enum.h" -#include "Task/Task.enum.h" -#include "Trade.enum.h" +#include "../Account.enum.h" +#include "../Chart.enum.h" +#include "../Data.struct.h" +#include "../EA.enum.h" +#include "../Indicator.enum.h" +#include "TaskAction.enum.h" +//#include "../Market.enum.h" +#include "../Order.enum.h" +#include "../Serializer.mqh" +#include "../Strategy.enum.h" +#include "../Trade.enum.h" +#include "Task.enum.h" -/* Entry for Action class. */ -struct ActionEntry { - unsigned char flags; /* Action flags. */ +/* Entry for TaskAction class. */ +struct TaskActionEntry { + unsigned char flags; /* TaskAction flags. */ datetime last_success; /* Time of the previous check. */ int frequency; /* How often to check. */ - long action_id; /* Action ID. */ + long action_id; /* TaskAction ID. */ short tries; /* Number of retries left. */ void *obj; /* Reference to associated object. */ - ENUM_ACTION_TYPE type; /* Action type. */ - DataParamEntry args[]; /* Action arguments. */ + ENUM_ACTION_TYPE type; /* TaskAction type. */ + DataParamEntry args[]; /* TaskAction arguments. */ // Constructors. - ActionEntry() : type(FINAL_ACTION_TYPE_ENTRY), action_id(WRONG_VALUE) { Init(); } - ActionEntry(long _action_id, ENUM_ACTION_TYPE _type) : type(_type), action_id(_action_id) { Init(); } - ActionEntry(ActionEntry &_ae) { this = _ae; } - ActionEntry(ENUM_EA_ACTION _action_id) : type(ACTION_TYPE_EA), action_id(_action_id) { Init(); } - ActionEntry(ENUM_ORDER_ACTION _action_id) : type(ACTION_TYPE_ORDER), action_id(_action_id) { Init(); } - ActionEntry(ENUM_INDICATOR_ACTION _action_id) : type(ACTION_TYPE_INDICATOR), action_id(_action_id) { Init(); } - ActionEntry(ENUM_STRATEGY_ACTION _action_id) : type(ACTION_TYPE_STRATEGY), action_id(_action_id) { Init(); } - ActionEntry(ENUM_TASK_ACTION _action_id) : type(ACTION_TYPE_TASK), action_id(_action_id) { Init(); } - ActionEntry(ENUM_TRADE_ACTION _action_id) : type(ACTION_TYPE_TRADE), action_id(_action_id) { Init(); } + TaskActionEntry() : type(FINAL_ACTION_TYPE_ENTRY), action_id(WRONG_VALUE) { Init(); } + TaskActionEntry(long _action_id, ENUM_ACTION_TYPE _type) : type(_type), action_id(_action_id) { Init(); } + TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } + TaskActionEntry(ENUM_EA_ACTION _action_id) : type(ACTION_TYPE_EA), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_ORDER_ACTION _action_id) : type(ACTION_TYPE_ORDER), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_INDICATOR_ACTION _action_id) : type(ACTION_TYPE_INDICATOR), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_STRATEGY_ACTION _action_id) : type(ACTION_TYPE_STRATEGY), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_TASK_ACTION _action_id) : type(ACTION_TYPE_TASK), action_id(_action_id) { Init(); } + TaskActionEntry(ENUM_TRADE_ACTION _action_id) : type(ACTION_TYPE_TRADE), action_id(_action_id) { Init(); } // Deconstructor. - ~ActionEntry() { + ~TaskActionEntry() { // Object::Delete(obj); } // Flag methods. diff --git a/Task/TaskCondition.enum.h b/Task/TaskCondition.enum.h index 25faf93a4..13cb5542c 100644 --- a/Task/TaskCondition.enum.h +++ b/Task/TaskCondition.enum.h @@ -104,7 +104,7 @@ enum ENUM_TASK_CONDITION_STATEMENT { /* Defines condition types. */ enum ENUM_TASK_CONDITION_TYPE { COND_TYPE_ACCOUNT = 1, // Account condition. - COND_TYPE_ACTION, // Action condition. + COND_TYPE_ACTION, // TaskAction condition. COND_TYPE_CHART, // Chart condition. COND_TYPE_DATETIME, // Datetime condition. COND_TYPE_EA, // EA condition. @@ -164,7 +164,7 @@ enum ENUM_ACCOUNT_CONDITION { FINAL_ACCOUNT_CONDITION_ENTRY }; -/* Action conditions. */ +/* TaskAction conditions. */ enum ENUM_ACTION_CONDITION { ACTION_COND_NONE = 0, // Empty condition. ACTION_COND_IS_ACTIVE, // Is active. diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index f84783996..5b38c12df 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -28,10 +28,11 @@ struct DataParamEntry; // Includes. -#include "../../Action.mqh" #include "../../Chart.mqh" #include "../../DictObject.mqh" #include "../../EA.mqh" +#include "../TaskAction.h" +#include "../TaskCondition.h" #include "../../Test.mqh" #include "../Task.h" diff --git a/tests/ActionTest.mq4 b/Task/tests/TaskAction.test.mq4 similarity index 93% rename from tests/ActionTest.mq4 rename to Task/tests/TaskAction.test.mq4 index 5aba4100d..080ea3c49 100644 --- a/tests/ActionTest.mq4 +++ b/Task/tests/TaskAction.test.mq4 @@ -21,8 +21,8 @@ /** * @file - * Test functionality of Action class. + * Test functionality of TaskAction class. */ // Includes. -#include "ActionTest.mq5" +#include "TaskAction.test.mq5" diff --git a/tests/ActionTest.mq5 b/Task/tests/TaskAction.test.mq5 similarity index 92% rename from tests/ActionTest.mq5 rename to Task/tests/TaskAction.test.mq5 index f5a8ece2c..475530773 100644 --- a/tests/ActionTest.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -21,7 +21,7 @@ /** * @file - * Test functionality of Action class. + * Test functionality of TaskAction class. */ // Defines. @@ -31,15 +31,15 @@ struct DataParamEntry; // Includes. -#include "../Action.mqh" -#include "../DictObject.mqh" -#include "../EA.mqh" -#include "../Test.mqh" +#include "../../DictObject.mqh" +#include "../../EA.mqh" +#include "../../Test.mqh" +#include "../TaskAction.h" // Global variables. Chart *chart; EA *ea; -DictObject actions; +DictObject actions; // Define strategy classes. class Stg1 : public Strategy { @@ -79,12 +79,12 @@ int OnInit() { assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); #ifdef ACTION_EA_ENABLED // Disables EA and confirm it's disabled. - Action *action1 = new Action(EA_ACTION_DISABLE, ea); + TaskAction *action1 = new TaskAction(EA_ACTION_DISABLE, ea); action1.Execute(); assertTrueOrReturnFalse(!ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); delete action1; // Re-enables EA and confirm it's enabled. - Action *action2 = new Action(EA_ACTION_ENABLE, ea); + TaskAction *action2 = new TaskAction(EA_ACTION_ENABLE, ea); action2.Execute(); assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); delete action2; diff --git a/Trade.mqh b/Trade.mqh index 78877e5e7..d4ab21fa9 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -31,7 +31,6 @@ class Trade; // Includes. #include "Account.mqh" -#include "Action.enum.h" #include "Chart.mqh" #include "Convert.mqh" #include "DictStruct.mqh" @@ -39,6 +38,7 @@ class Trade; #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" +#include "Task/TaskAction.enum.h" #include "Task/TaskCondition.enum.h" #include "Trade.enum.h" #include "Trade.struct.h" @@ -1810,7 +1810,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return Trade::CheckCondition(_cond, _args); } - /* Actions */ + /* TaskActions */ /** * Execute trade action. diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index aa40a93cb..1f5648d64 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -26,8 +26,8 @@ // Includes. #include "../Account.mqh" -#include "../Action.mqh" #include "../Array.mqh" +#include "../Task/TaskAction.h" //#include "../BasicTrade.mqh" // @removeme #include "../Buffer.mqh" #include "../BufferStruct.mqh" From a2a642dfd7fa34705c344bb2ac2e1a25de46a905 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 19:30:39 +0100 Subject: [PATCH 32/97] TaskAction: Initial code refactor --- EA.mqh | 2 + EA.struct.h | 2 +- Indicators/Indi_Drawer.mqh | 6 +- Strategy.mqh | 2 + Task/Task.h | 2 + Task/Task.struct.h | 21 +-- Task/TaskAction.enum.h | 9 - Task/TaskAction.h | 330 ++++----------------------------- Task/TaskAction.struct.h | 154 +++++++++------ Task/TaskActionBase.h | 52 ++++++ Task/tests/Task.test.mq5 | 4 +- Task/tests/TaskAction.test.mq5 | 111 ++++------- tests/EATest.mq5 | 6 +- 13 files changed, 248 insertions(+), 453 deletions(-) create mode 100644 Task/TaskActionBase.h diff --git a/EA.mqh b/EA.mqh index 54aef90b3..e1ac8fff3 100644 --- a/EA.mqh +++ b/EA.mqh @@ -617,6 +617,7 @@ class EA { */ bool TaskAdd(TaskEntry &_entry) { bool _result = false; + /* @fixme if (_entry.IsValid()) { switch (_entry.GetConditionType()) { case COND_TYPE_ACCOUNT: @@ -639,6 +640,7 @@ class EA { } _result |= tasks.Push(_entry); } + */ return _result; } diff --git a/EA.struct.h b/EA.struct.h index a750d2e11..dca307294 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -195,7 +195,7 @@ struct EAParams { ver = _ver; author = _author; } - void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } + //void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } // Printers. string ToString(string _dlm = ",") { return StringFormat("%s v%s by %s (%s)", name, ver, author, desc); } }; diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index d5878da2e..fb8e22c2e 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -114,6 +114,7 @@ class Indi_Drawer : public Indicator { virtual void OnTick() { Indicator::OnTick(); + /* @fixme TaskActionEntry action(INDI_ACTION_SET_VALUE); ArrayResize(action.args, 3); action.args[0].type = TYPE_LONG; @@ -124,9 +125,11 @@ class Indi_Drawer : public Indicator { action.args[2].type = TYPE_DOUBLE; action.args[2].double_value = 1.25; + */ - string json = SerializerConverter::FromObject(action).ToString(/*SERIALIZER_JSON_NO_WHITESPACES*/); + //string json = SerializerConverter::FromObject(action).ToString(/*SERIALIZER_JSON_NO_WHITESPACES*/); + /* @fixme RedisMessage msg; msg.Add("message"); msg.Add("INDICATOR_DRAW"); @@ -151,6 +154,7 @@ class Indi_Drawer : public Indicator { // Drawing on the buffer. } } + */ } Redis *Redis() { return &redis; } diff --git a/Strategy.mqh b/Strategy.mqh index 3823f986f..e23a3adcb 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -238,12 +238,14 @@ class Strategy : public Object { */ void AddTask(TaskEntry &_entry) { if (_entry.IsValid()) { + /* @fixme if (_entry.GetAction().GetType() == ACTION_TYPE_STRATEGY) { _entry.SetActionObject(GetPointer(this)); } if (_entry.GetCondition().GetType() == COND_TYPE_STRATEGY) { _entry.SetConditionObject(GetPointer(this)); } + */ tasks.Push(_entry); } } diff --git a/Task/Task.h b/Task/Task.h index 4c5863a32..cec38d381 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -97,6 +97,7 @@ class Task { */ static bool Process(TaskEntry &_entry) { bool _result = false; + /* @fixme if (_entry.IsActive()) { if (TaskCondition::Test(_entry.GetCondition())) { TaskActionEntry _action = _entry.GetAction(); @@ -111,6 +112,7 @@ class Task { _entry.last_process = TimeCurrent(); _result = true; } + */ return _result; } diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 4c9b328d0..15ec0aac9 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -45,13 +45,8 @@ struct TaskEntry { // Constructors. void TaskEntry() { Init(); } void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } - void TaskEntry(long _aid, ENUM_ACTION_TYPE _atype, long _cid, ENUM_TASK_CONDITION_TYPE _ctype) - : action(_aid, _atype), cond(_cid, _ctype) { - Init(); - } template - void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { - Init(); + void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { : action(_aid, _atype), cond(_cid, _ctype){Init()}; } // Main methods. void Init() { @@ -72,18 +67,16 @@ struct TaskEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } - bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } - bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } - bool IsValid() { return !HasFlag(ACTION_ENTRY_FLAG_IS_INVALID); } + // bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } + // bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } + // bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } + bool IsValid() { return action.IsValid() && cond.IsValid(); } // Getters. long GetActionId() { return action.GetId(); } long GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } - ENUM_ACTION_TYPE GetActionType() { return action.GetType(); } - ENUM_TASK_CONDITION_TYPE GetConditionType() { return cond.GetType(); } // Setters. - void SetActionObject(void *_obj) { action.SetObject(_obj); } - void SetConditionObject(void *_obj) { cond.SetObject(_obj); } + // void SetActionObject(void *_obj) { action.SetObject(_obj); } + // void SetConditionObject(void *_obj) { cond.SetObject(_obj); } }; diff --git a/Task/TaskAction.enum.h b/Task/TaskAction.enum.h index ed6a40cb6..3756722ea 100644 --- a/Task/TaskAction.enum.h +++ b/Task/TaskAction.enum.h @@ -33,15 +33,6 @@ #ifndef ACTION_ENUM_H #define ACTION_ENUM_H -/* Defines action entry flags. */ -enum ENUM_ACTION_ENTRY_FLAGS { - ACTION_ENTRY_FLAG_NONE = 0, - ACTION_ENTRY_FLAG_IS_ACTIVE = 1, - ACTION_ENTRY_FLAG_IS_DONE = 2, - ACTION_ENTRY_FLAG_IS_FAILED = 4, - ACTION_ENTRY_FLAG_IS_INVALID = 8 -}; - /* Defines action types. */ enum ENUM_ACTION_TYPE { ACTION_TYPE_NONE = 0, // None. diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 15650d050..859544eec 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -26,30 +26,22 @@ */ // Prevents processing this includes file for the second time. -#ifndef ACTION_MQH -#define ACTION_MQH - -// Forward class declaration. -class TaskAction; +#ifndef TASK_ACTION_MQH +#define TASK_ACTION_MQH // Includes. -#include "../EA.mqh" #include "TaskAction.enum.h" #include "TaskAction.struct.h" -#include "TaskCondition.enum.h" /** * TaskAction class. */ -class TaskAction { - public: - protected: - // Class variables. - Ref logger; - +template +class TaskAction : TaskActionBase { public: // Class variables. - DictStruct actions; + TaskActionEntry entry; // Action entry. + TO obj; // Object to run the action on. /* Special methods */ @@ -57,317 +49,67 @@ class TaskAction { * Class constructor. */ TaskAction() {} - TaskAction(TaskActionEntry &_entry) { actions.Push(_entry); } - TaskAction(long _action_id, ENUM_ACTION_TYPE _type) { - TaskActionEntry _entry(_action_id, _type); - actions.Push(_entry); - } - template - TaskAction(T _action_id, void *_obj = NULL) { - TaskActionEntry _entry(_action_id); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - actions.Push(_entry); - } - template - TaskAction(T _action_id, MqlParam &_args[], void *_obj = NULL) { - TaskActionEntry _entry(_action_id); - _entry.SetArgs(_args); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - actions.Push(_entry); - } - - /** - * Class copy constructor. - */ - TaskAction(TaskAction &_cond) { actions = _cond.GetActions(); } + TaskAction(TaskActionEntry &_entry) : entry(_entry) {} /* Main methods */ /** - * Execute actions. - */ - bool Execute() { - bool _result = true, _executed = false; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - bool _curr_result = false; - TaskActionEntry _entry = iter.Value(); - if (!_entry.IsValid()) { - // Ignore invalid entries. - continue; - } - if (_entry.IsActive()) { - _executed = _result &= Execute(_entry); - } - } - return _result && _executed; - } - - /** - * Execute specific action. + * Runs an action. */ - static bool Execute(TaskActionEntry &_entry) { - bool _result = false; - switch (_entry.type) { - case ACTION_TYPE_ACTION: - if (Object::IsValid(_entry.obj)) { - _result = ((TaskAction *)_entry.obj).ExecuteAction((ENUM_ACTION_ACTION)_entry.action_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; - case ACTION_TYPE_EA: - if (Object::IsValid(_entry.obj)) { - _result = ((EA *)_entry.obj).ExecuteAction((ENUM_EA_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef ORDER_MQH - case ACTION_TYPE_ORDER: - if (Object::IsValid(_entry.obj)) { - _result = ((Order *)_entry.obj).ExecuteAction((ENUM_ORDER_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef INDICATOR_MQH - case ACTION_TYPE_INDICATOR: - if (Object::IsValid(_entry.obj)) { - _result = ((Indicator *)_entry.obj).ExecuteAction((ENUM_INDICATOR_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef STRATEGY_MQH - case ACTION_TYPE_STRATEGY: - if (Object::IsValid(_entry.obj)) { - _result = ((Strategy *)_entry.obj).ExecuteAction((ENUM_STRATEGY_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef TASK_MQH - case ACTION_TYPE_TASK: - if (Object::IsValid(_entry.obj)) { - _result = ((Task *)_entry.obj).ExecuteAction((ENUM_TASK_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - case ACTION_TYPE_TRADE: - if (Object::IsValid(_entry.obj)) { - _result = ((Trade *)_entry.obj).ExecuteAction((ENUM_TRADE_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef TERMINAL_MQH - case ACTION_TYPE_TERMINAL: - if (Object::IsValid(_entry.obj)) { - _result = ((Terminal *)_entry.obj).ExecuteAction((ENUM_TERMINAL_ACTION)_entry.action_id); - } else { - _result = false; - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - } + bool Run() { + bool _result = entry.IsValid() && entry.HasTriesLeft(); + _result &= obj.Run(entry); if (_result) { - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_DONE); - _entry.RemoveFlags(ACTION_ENTRY_FLAG_IS_ACTIVE); - _entry.last_success = TimeCurrent(); + entry.TriesDec(); + entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); + entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); + entry.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_TIME_LAST_RUN), TimeCurrent()); } else { - if (--_entry.tries <= 0) { - _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID); - _entry.RemoveFlags(ACTION_ENTRY_FLAG_IS_ACTIVE); + entry.TriesDec(); + if (!entry.HasTriesLeft()) { + entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); + entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } } return _result; } - /* State methods */ - - /** - * Check if action is active. - */ - bool IsActive() { - // The whole action is active when at least one action is active. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_ACTIVE) > 0; - } - - /** - * Check if action is done. - */ - bool IsDone() { - // The whole action is done when all actions has been executed successfully. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_DONE) == actions.Size(); - } - - /** - * Check if action has failed. - */ - bool IsFailed() { - // The whole action is failed when at least one action failed. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_FAILED) > 0; - } - - /** - * Check if action is finished. - */ - bool IsFinished() { - // The whole action is finished when there are no more active actions. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_ACTIVE) == 0; - } - - /** - * Check if action is invalid. - */ - bool IsInvalid() { - // The whole action is invalid when at least one action is invalid. - return GetFlagCount(ACTION_ENTRY_FLAG_IS_INVALID) > 0; - } - /* Getters */ /** - * Returns actions. + * Gets an entry's flag. */ - DictStruct *GetActions() { return &actions; } + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) const { return entry.Get(_flag); } /** - * Count entry flags. + * Gets an entry's property value. */ - unsigned int GetFlagCount(ENUM_ACTION_ENTRY_FLAGS _flag) { - unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - TaskActionEntry _entry = iter.Value(); - if (_entry.HasFlag(_flag)) { - _counter++; - } - } - return _counter; + template + T Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) const { + entry.Get(_prop); } - /* Setters */ - /** - * Sets entry flags. + * Gets an reference to the object. */ - bool SetFlags(ENUM_ACTION_ENTRY_FLAGS _flag, bool _value = true) { - unsigned int _counter = 0; - for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) { - TaskActionEntry _entry = iter.Value(); - switch (_value) { - case false: - if (_entry.HasFlag(_flag)) { - _entry.SetFlag(_flag, _value); - _counter++; - } - break; - case true: - if (!_entry.HasFlag(_flag)) { - _entry.SetFlag(_flag, _value); - _counter++; - } - break; - } - } - return _counter > 0; - } + TO *GetObject() { return GetPointer(obj); } - /* Conditions and actions */ + /* Setters */ /** - * Checks for Task condition. - * - * @param ENUM_ACTION_CONDITION _cond - * TaskAction condition. - * @return - * Returns true when the condition is met. + * Sets an entry's flag. */ - bool CheckCondition(ENUM_ACTION_CONDITION _cond, DataParamEntry &_args[]) { - switch (_cond) { - case ACTION_COND_IS_ACTIVE: - // Is active; - return IsActive(); - case ACTION_COND_IS_DONE: - // Is done. - return IsDone(); - case ACTION_COND_IS_FAILED: - // Is failed. - return IsFailed(); - case ACTION_COND_IS_FINISHED: - // Is finished. - return IsFinished(); - case ACTION_COND_IS_INVALID: - // Is invalid. - return IsInvalid(); - default: - logger.Ptr().Error(StringFormat("Invalid TaskAction condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; - } - } - bool CheckCondition(ENUM_ACTION_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return TaskAction::CheckCondition(_cond, _args); + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { + entry.Set(_flag, _value); } /** - * Execute action of action. - * - * @param ENUM_ACTION_ACTION _action - * TaskAction of action to execute. - * @return - * Returns true when the action has been executed successfully. + * Sets an entry's property value. */ - bool ExecuteAction(ENUM_ACTION_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; - switch (_action) { - case ACTION_ACTION_DISABLE: - // Disable action. - return SetFlags(ACTION_ENTRY_FLAG_IS_ACTIVE, false); - case ACTION_ACTION_EXECUTE: - // Execute action. - return Execute(); - case ACTION_ACTION_MARK_AS_DONE: - // Marks as done. - return SetFlags(ACTION_ENTRY_FLAG_IS_DONE); - case ACTION_ACTION_MARK_AS_FAILED: - // Mark as failed. - return SetFlags(ACTION_ENTRY_FLAG_IS_FAILED); - case ACTION_ACTION_MARK_AS_FINISHED: - // Mark as finished. - return SetFlags(ACTION_ENTRY_FLAG_IS_ACTIVE, false); - case ACTION_ACTION_MARK_AS_INVALID: - // Mark as invalid. - return SetFlags(ACTION_ENTRY_FLAG_IS_INVALID); - default: - logger.Ptr().Error(StringFormat("Invalid action of action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - return false; - } - return _result; - } - bool ExecuteAction(ENUM_ACTION_ACTION _action) { - ARRAY(DataParamEntry, _args); - return TaskAction::ExecuteAction(_action, _args); + template + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); } - - /* Other methods */ }; -#endif // ACTION_MQH +#endif // TASK_ACTION_MQH diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 21434aa67..7c7d08138 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -30,88 +30,126 @@ #endif // Includes. -#include "../Account.enum.h" -#include "../Chart.enum.h" #include "../Data.struct.h" -#include "../EA.enum.h" -#include "../Indicator.enum.h" -#include "TaskAction.enum.h" -//#include "../Market.enum.h" -#include "../Order.enum.h" -#include "../Serializer.mqh" -#include "../Strategy.enum.h" -#include "../Trade.enum.h" +#include "../Std.h" #include "Task.enum.h" /* Entry for TaskAction class. */ struct TaskActionEntry { - unsigned char flags; /* TaskAction flags. */ - datetime last_success; /* Time of the previous check. */ - int frequency; /* How often to check. */ - long action_id; /* TaskAction ID. */ - short tries; /* Number of retries left. */ - void *obj; /* Reference to associated object. */ - ENUM_ACTION_TYPE type; /* TaskAction type. */ - DataParamEntry args[]; /* TaskAction arguments. */ + public: + // Defines enumerations. + enum ENUM_TASK_ACTION_ENTRY_PROP { + TASK_ACTION_ENTRY_FLAGS, + TASK_ACTION_ENTRY_FREQUENCY, + TASK_ACTION_ENTRY_ID, + TASK_ACTION_ENTRY_TRIES, + TASK_ACTION_ENTRY_TIME_LAST_RUN, + }; + /* Defines action entry flags. */ + enum ENUM_TASK_ACTION_ENTRY_FLAG { + TASK_ACTION_ENTRY_FLAG_NONE = 0 << 0, + TASK_ACTION_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_ACTION_ENTRY_FLAG_IS_DONE = 1 << 1, + TASK_ACTION_ENTRY_FLAG_IS_FAILED = 1 << 2, + TASK_ACTION_ENTRY_FLAG_IS_INVALID = 1 << 3, + }; + + protected: + unsigned char flags; /* TaskAction flags. */ + datetime time_last_run; /* Time of the successful run. */ + int freq; /* How often to run (0 for no limit). */ + long id; /* TaskAction's enum ID. */ + short tries; /* Number of retries left. */ + DataParamEntry args[]; /* TaskAction arguments. */ + public: // Constructors. - TaskActionEntry() : type(FINAL_ACTION_TYPE_ENTRY), action_id(WRONG_VALUE) { Init(); } - TaskActionEntry(long _action_id, ENUM_ACTION_TYPE _type) : type(_type), action_id(_action_id) { Init(); } + TaskActionEntry() : flags(0), freq(0), id(WRONG_VALUE), time_last_run(0), tries(0) {} + TaskActionEntry(long _id) + : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), time_last_run(0), tries(0) {} TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } - TaskActionEntry(ENUM_EA_ACTION _action_id) : type(ACTION_TYPE_EA), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_ORDER_ACTION _action_id) : type(ACTION_TYPE_ORDER), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_INDICATOR_ACTION _action_id) : type(ACTION_TYPE_INDICATOR), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_STRATEGY_ACTION _action_id) : type(ACTION_TYPE_STRATEGY), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_TASK_ACTION _action_id) : type(ACTION_TYPE_TASK), action_id(_action_id) { Init(); } - TaskActionEntry(ENUM_TRADE_ACTION _action_id) : type(ACTION_TYPE_TRADE), action_id(_action_id) { Init(); } - // Deconstructor. - ~TaskActionEntry() { - // Object::Delete(obj); - } // Flag methods. - bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } - void SetFlag(ENUM_ACTION_ENTRY_FLAGS _flag, bool _value) { - if (_value) + void SetFlag(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value) { + if (_value) { AddFlags(_flag); - else + } else { RemoveFlags(_flag); + } } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } - bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } - bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } - bool IsInvalid() { return HasFlag(ACTION_ENTRY_FLAG_IS_INVALID); } - bool IsValid() { return !IsInvalid(); } + bool HasTriesLeft() const { return tries > 0; } + bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } + bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); } + bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED)); } + bool IsInvalid() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); } + bool IsValid() const { return !IsInvalid(); } // Getters. - long GetId() { return action_id; } - ENUM_ACTION_TYPE GetType() { return type; } - // Setter methods. + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_ACTION_ENTRY_FLAGS: + return (T)flags; + case TASK_ACTION_ENTRY_FREQUENCY: + return (T)freq; + case TASK_ACTION_ENTRY_ID: + return (T)id; + case TASK_ACTION_ENTRY_TRIES: + return (T)tries; + case TASK_ACTION_ENTRY_TIME_LAST_RUN: + return (T)time_last_run; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + long GetId() const { return id; } + // Setters. + void TriesDec() { tries--; } + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_ACTION_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_ACTION_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_ACTION_ENTRY_ID: + id = (long)_value; + SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_ACTION_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_ACTION_ENTRY_TIME_LAST_RUN: + time_last_run = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } void AddArg(MqlParam &_arg) { // @todo: Add another value to args[]. } - void Init() { - flags = ACTION_ENTRY_FLAG_NONE; - frequency = 60; - SetFlag(ACTION_ENTRY_FLAG_IS_ACTIVE, action_id != WRONG_VALUE); - SetFlag(ACTION_ENTRY_FLAG_IS_INVALID, action_id == WRONG_VALUE); - last_success = 0; - tries = 1; - } void SetArgs(ARRAY_REF(MqlParam, _args)) { // @todo: for(). } - void SetObject(void *_obj) { obj = _obj; } - void SetTries(short _count) { tries = _count; } - + // Serializers SerializerNodeType Serialize(Serializer &s) { s.Pass(THIS_REF, "flags", flags); - s.Pass(THIS_REF, "last_success", last_success); - s.Pass(THIS_REF, "action_id", action_id); - // s.Pass(THIS_REF, "tries", tries); - s.PassEnum(THIS_REF, "type", type); - s.PassEnum(THIS_REF, "frequency", frequency); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_run", time_last_run); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); s.PassArray(this, "args", args); return SerializerNodeObject; } diff --git a/Task/TaskActionBase.h b/Task/TaskActionBase.h new file mode 100644 index 000000000..3b4a6ed9a --- /dev/null +++ b/Task/TaskActionBase.h @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides a base class for a task's action. + */ + +// Prevents processing this includes file for the second time. +#ifndef TASK_ACTION_BASE_MQH +#define TASK_ACTION_BASE_MQH + +/** + * TaskActionBase class. + */ +class TaskActionBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskActionBase() {} + + /* Main methods */ + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry); +}; + +#endif // TASK_ACTION_BASE_MQH diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 5b38c12df..31be5230c 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -31,10 +31,10 @@ struct DataParamEntry; #include "../../Chart.mqh" #include "../../DictObject.mqh" #include "../../EA.mqh" -#include "../TaskAction.h" -#include "../TaskCondition.h" #include "../../Test.mqh" #include "../Task.h" +#include "../TaskAction.h" +#include "../TaskCondition.h" // Global variables. Chart *chart; diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 475530773..3b7d3dec5 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -24,40 +24,42 @@ * Test functionality of TaskAction class. */ -// Defines. -#define ACTION_EA_ENABLED - -// Forward declaration. -struct DataParamEntry; - // Includes. -#include "../../DictObject.mqh" -#include "../../EA.mqh" #include "../../Test.mqh" #include "../TaskAction.h" +#include "../TaskActionBase.h" + +enum ENUM_TASK_ACTION_TEST { + TASK_ACTION_TEST01 = 1, + TASK_ACTION_TEST02 = 2, + TASK_ACTION_TEST03 = 3, +}; -// Global variables. -Chart *chart; -EA *ea; -DictObject actions; +class TaskActionTest01 : public TaskActionBase { + protected: + long sum; -// Define strategy classes. -class Stg1 : public Strategy { public: - void Stg1(StgParams &_params, TradeParams &_tparams, ChartParams &_cparams, string _name = "Stg1") - : Strategy(_params, _tparams, _cparams, _name) {} - static Stg1 *Init(ENUM_TIMEFRAMES _tf = NULL, unsigned long _magic_no = 0, ENUM_LOG_LEVEL _log_level = V_INFO) { - ChartParams _cparams(_tf); - TradeParams _tparams(_magic_no, _log_level); - Strategy *_strat = new Stg1(stg_params_defaults, _tparams, _cparams, __FUNCTION__); - return _strat; + TaskActionTest01() : sum(0){}; + long GetSum() { return sum; } + bool Run(const TaskActionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + return true; } - bool SignalOpen(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - bool SignalOpenFilterMethod(ENUM_ORDER_TYPE _cmd, int _method = 0) { return true; } - float SignalOpenBoost(ENUM_ORDER_TYPE _cmd, int _method = 0) { return 1.0; } - bool SignalClose(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - float PriceStop(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_TYPE_VALUE _mode, int _method = 0, float _level = 0.0f) { - return _level; +}; + +class TaskActionTest02 : public TaskActionBase { + protected: + long sum; + + public: + TaskActionTest02() : sum(0){}; + long GetSum() { return sum; } + bool Run(const TaskActionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + return true; } }; @@ -66,58 +68,25 @@ class Stg1 : public Strategy { */ int OnInit() { bool _result = true; - // Initializes chart. - chart = new Chart(); - // Initializes EA. - EAParams ea_params(__FILE__); - ea = new EA(ea_params); - _result &= ea.StrategyAdd(127); - // Check asserts. - // Confirm EA is active. - assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ACTIVE), "Wrong condition: EA_COND_IS_ACTIVE!"); - // Confirm EA is enabled. - assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); -#ifdef ACTION_EA_ENABLED - // Disables EA and confirm it's disabled. - TaskAction *action1 = new TaskAction(EA_ACTION_DISABLE, ea); - action1.Execute(); - assertTrueOrReturnFalse(!ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); - delete action1; - // Re-enables EA and confirm it's enabled. - TaskAction *action2 = new TaskAction(EA_ACTION_ENABLE, ea); - action2.Execute(); - assertTrueOrReturnFalse(ea.CheckCondition(EA_COND_IS_ENABLED), "Wrong condition: EA_COND_IS_ENABLED!"); - delete action2; -#endif + // Test01 + TaskActionEntry _entry01(TASK_ACTION_TEST01); + TaskAction _action01(_entry01); + _action01.Run(); + _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST02); + _action01.Run(); + _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); + _action01.Run(); + assertTrueOrFail(_action01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; - return (_result ? INIT_SUCCEEDED : INIT_FAILED); } /** * Implements Tick event handler. */ -void OnTick() { - chart.OnTick(); - if (chart.IsNewBar()) { - unsigned int _bar_index = chart.GetBarIndex(); - switch (_bar_index) { - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - break; - } - } -} +void OnTick() {} /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { - delete chart; - delete ea; -} +void OnDeinit(const int reason) {} diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 31d11e524..176be0a21 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -59,7 +59,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params.SetTaskEntry(_task_export_per_hour); + //ea_params.SetTaskEntry(_task_export_per_hour); ea = new EA(ea_params); assertTrueOrFail(ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA", StringFormat("Invalid EA name: %s!", ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); @@ -69,7 +69,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params1.SetTaskEntry(_task_export_per_hour); + //ea_params1.SetTaskEntry(_task_export_per_hour); ea1 = new EA1(ea_params1); assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", "Invalid EA1 name!"); @@ -78,7 +78,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params2.SetTaskEntry(_task_export_per_hour); + //ea_params2.SetTaskEntry(_task_export_per_hour); ea2 = new EA2(ea_params2); assertTrueOrFail(ea2.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA2", "Invalid EA2 name!"); From 02232347f72a8767f2a59487efba8a217d8caa00 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 6 Oct 2021 19:34:25 +0100 Subject: [PATCH 33/97] GHA: Adds tests for Task-related classes --- .github/workflows/test-task.yml | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/test-task.yml diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml new file mode 100644 index 000000000..36ed3cbf9 --- /dev/null +++ b/.github/workflows/test-task.yml @@ -0,0 +1,61 @@ +--- +name: Test Task + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Task/**.h' + - '.github/workflows/test-task.yml' + push: + paths: + - 'Task/**.h' + - '.github/workflows/test-task.yml' + +jobs: + + Compile: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + uses: fx31337/mql-compile-action@master + with: + init-platform: true + path: 'Task/tests' + verbose: true + - name: Print compiled files + run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' + shell: powershell + - name: Upload artifacts (MQL4) + uses: actions/upload-artifact@v2 + with: + name: files-ex4 + path: '**/*.ex4' + - name: Upload artifacts (MQL5) + uses: actions/upload-artifact@v2 + with: + name: files-ex5 + path: '**/*.ex5' + + Task-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Task/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Task.test + - TaskAction.test + - TaskCondition.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} From a8ebb4a64f882b8a48414fa2c5be1f7d6159dbf5 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 24 Oct 2021 20:41:08 +0100 Subject: [PATCH 34/97] TaskCondition: Code refactor --- Task/Task.h | 11 +- Task/Task.struct.h | 5 +- Task/TaskAction.h | 43 ++++-- Task/TaskAction.struct.h | 20 ++- Task/TaskActionBase.h | 13 +- Task/TaskCondition.enum.h | 9 -- Task/TaskCondition.h | 222 +++++++++--------------------- Task/TaskCondition.struct.h | 142 ++++++++++++++----- Task/TaskConditionBase.h | 57 ++++++++ Task/tests/TaskCondition.test.mq5 | 197 +++++++------------------- 10 files changed, 340 insertions(+), 379 deletions(-) create mode 100644 Task/TaskConditionBase.h diff --git a/Task/Task.h b/Task/Task.h index cec38d381..d6a718f02 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -25,9 +25,14 @@ * Provides integration with tasks (manages conditions and actions). */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_MQH -#define TASK_MQH +#ifndef TASK_H +#define TASK_H // Includes. #include "../DictStruct.mqh" @@ -270,4 +275,4 @@ class Task { /* Other methods */ }; -#endif // TASK_MQH +#endif // TASK_H diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 15ec0aac9..82e7b6684 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -46,8 +46,9 @@ struct TaskEntry { void TaskEntry() { Init(); } void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } template - void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { : action(_aid, _atype), cond(_cid, _ctype){Init()}; - } + void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { + Init(); + }; // Main methods. void Init() { flags = TASK_ENTRY_FLAG_NONE; diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 859544eec..56ed17fe2 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -25,9 +25,14 @@ * Provides integration with actions. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_ACTION_MQH -#define TASK_ACTION_MQH +#ifndef TASK_ACTION_H +#define TASK_ACTION_H // Includes. #include "TaskAction.enum.h" @@ -38,42 +43,52 @@ */ template class TaskAction : TaskActionBase { - public: - // Class variables. + protected: + // Protected class variables. TaskActionEntry entry; // Action entry. TO obj; // Object to run the action on. + public: /* Special methods */ /** - * Class constructor. + * Default class constructor. */ TaskAction() {} + + /** + * Class constructor with an entry as argument. + */ TaskAction(TaskActionEntry &_entry) : entry(_entry) {} /* Main methods */ /** - * Runs an action. + * Runs a current action. */ bool Run() { bool _result = entry.IsValid() && entry.HasTriesLeft(); _result &= obj.Run(entry); if (_result) { - entry.TriesDec(); entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); entry.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_TIME_LAST_RUN), TimeCurrent()); } else { - entry.TriesDec(); - if (!entry.HasTriesLeft()) { - entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); - entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); - } + entry.AddFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID)); + entry.RemoveFlags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } + entry.TriesDec(); return _result; } + /** + * Runs a TaskAction action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + // @todo + return false; + } + /* Getters */ /** @@ -90,7 +105,7 @@ class TaskAction : TaskActionBase { } /** - * Gets an reference to the object. + * Gets s reference to the object. */ TO *GetObject() { return GetPointer(obj); } @@ -112,4 +127,4 @@ class TaskAction : TaskActionBase { } }; -#endif // TASK_ACTION_MQH +#endif // TASK_ACTION_H diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 7c7d08138..2518789f8 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -37,7 +37,9 @@ /* Entry for TaskAction class. */ struct TaskActionEntry { public: - // Defines enumerations. + /* Enumerations */ + + // Defines action entry properties. enum ENUM_TASK_ACTION_ENTRY_PROP { TASK_ACTION_ENTRY_FLAGS, TASK_ACTION_ENTRY_FREQUENCY, @@ -45,7 +47,7 @@ struct TaskActionEntry { TASK_ACTION_ENTRY_TRIES, TASK_ACTION_ENTRY_TIME_LAST_RUN, }; - /* Defines action entry flags. */ + // Defines action entry flags. enum ENUM_TASK_ACTION_ENTRY_FLAG { TASK_ACTION_ENTRY_FLAG_NONE = 0 << 0, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE = 1 << 0, @@ -61,11 +63,21 @@ struct TaskActionEntry { long id; /* TaskAction's enum ID. */ short tries; /* Number of retries left. */ DataParamEntry args[]; /* TaskAction arguments. */ + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + public: // Constructors. - TaskActionEntry() : flags(0), freq(0), id(WRONG_VALUE), time_last_run(0), tries(0) {} + TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(0) { Init(); } TaskActionEntry(long _id) - : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), time_last_run(0), tries(0) {} + : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), + id(_id), + freq(60), + time_last_run(0), + tries(0) { + Init(); + } TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } diff --git a/Task/TaskActionBase.h b/Task/TaskActionBase.h index 3b4a6ed9a..55c99c1e8 100644 --- a/Task/TaskActionBase.h +++ b/Task/TaskActionBase.h @@ -25,9 +25,14 @@ * Provides a base class for a task's action. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_ACTION_BASE_MQH -#define TASK_ACTION_BASE_MQH +#ifndef TASK_ACTION_BASE_H +#define TASK_ACTION_BASE_H /** * TaskActionBase class. @@ -46,7 +51,7 @@ class TaskActionBase { /** * Runs an action. */ - virtual bool Run(const TaskActionEntry &_entry); + virtual bool Run(const TaskActionEntry &_entry) = NULL; }; -#endif // TASK_ACTION_BASE_MQH +#endif // TASK_ACTION_BASE_H diff --git a/Task/TaskCondition.enum.h b/Task/TaskCondition.enum.h index 13cb5542c..3a8a9fbee 100644 --- a/Task/TaskCondition.enum.h +++ b/Task/TaskCondition.enum.h @@ -84,15 +84,6 @@ enum ENUM_MARKET_EVENT { }; #endif -/* Defines condition entry flags. */ -enum ENUM_TASK_CONDITION_ENTRY_FLAGS { - COND_ENTRY_FLAG_NONE = 0, - COND_ENTRY_FLAG_IS_ACTIVE = 1, - COND_ENTRY_FLAG_IS_EXPIRED = 2, - COND_ENTRY_FLAG_IS_INVALID = 4, - COND_ENTRY_FLAG_IS_READY = 8 -}; - /* Defines condition statements (operators). */ enum ENUM_TASK_CONDITION_STATEMENT { COND_AND = 1, // Use AND statement. diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index fc114af66..b51028f59 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -25,9 +25,14 @@ * Provides integration with conditions. */ +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + // Prevents processing this includes file for the second time. -#ifndef TASK_CONDITION_MQH -#define TASK_CONDITION_MQH +#ifndef TASK_CONDITION_H +#define TASK_CONDITION_H // Includes. #include "../Account.mqh" @@ -47,56 +52,33 @@ /** * TaskCondition class. */ +template class TaskCondition { public: protected: - // Class variables. - Ref logger; + // Protected class variables. + TaskConditionEntry entry; // Condition entry. + TC obj; // Object to run the action on. public: - // Class variables. - DictStruct conds; - /* Special methods */ /** - * Class constructor. + * Default class constructor. */ TaskCondition() {} - TaskCondition(TaskConditionEntry &_entry) { conds.Push(_entry); } - TaskCondition(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) { - TaskConditionEntry _entry(_cond_id, _type); - conds.Push(_entry); - } - template - TaskCondition(T _cond_id, void *_obj = NULL) { - TaskConditionEntry _entry(_cond_id); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - conds.Push(_entry); - } - template - TaskCondition(T _cond_id, MqlParam &_args[], void *_obj = NULL) { - Init(); - TaskConditionEntry _entry(_cond_id); - _entry.SetArgs(_args); - if (_obj != NULL) { - _entry.SetObject(_obj); - } - conds.Push(_entry); - } /** - * Class copy constructor. + * Class constructor with an entry as argument. */ - TaskCondition(TaskCondition &_cond) { conds = _cond.GetConditions(); } + TaskCondition(TaskConditionEntry &_entry) : entry(_entry) {} /* Main methods */ /** * Test conditions. */ + /* bool Test() { bool _result = false, _prev_result = true; for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { @@ -126,142 +108,70 @@ class TaskCondition { } return _result; } + */ /** - * Test specific condition. + * Checks a current condition. */ - static bool Test(TaskConditionEntry &_entry) { - bool _result = false; - switch (_entry.type) { - case COND_TYPE_ACCOUNT: - if (Object::IsValid(_entry.obj)) { - _result = ((Account *)_entry.obj).CheckCondition((ENUM_ACCOUNT_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; - case COND_TYPE_CHART: - if (Object::IsValid(_entry.obj)) { - _result = ((Chart *)_entry.obj).CheckCondition((ENUM_CHART_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; - case COND_TYPE_DATETIME: - if (Object::IsValid(_entry.obj)) { - _result = ((DateTime *)_entry.obj).CheckCondition((ENUM_DATETIME_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = DateTime::CheckCondition((ENUM_DATETIME_CONDITION)_entry.cond_id, _entry.args); - } - break; - case COND_TYPE_EA: - if (Object::IsValid(_entry.obj)) { - _result = ((EA *)_entry.obj).CheckCondition((ENUM_EA_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef INDICATOR_MQH - case COND_TYPE_INDICATOR: - if (Object::IsValid(_entry.obj)) { - _result = ((IndicatorBase *)_entry.obj).CheckCondition((ENUM_INDICATOR_CONDITION)_entry.cond_id, _entry.args); - } else { - // Static method not supported. - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - case COND_TYPE_MARKET: - if (Object::IsValid(_entry.obj)) { - _result = ((Market *)_entry.obj).CheckCondition((ENUM_MARKET_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef MATH_H - case COND_TYPE_MATH: - /* - if (Object::IsValid(_entry.obj)) { - _result = ((Math *)_entry.obj).CheckCondition((ENUM_MATH_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - */ - return false; - break; -#endif // MATH_M -#ifdef ORDER_MQH - case COND_TYPE_ORDER: - if (Object::IsValid(_entry.obj)) { - _result = ((Order *)_entry.obj).CheckCondition((ENUM_ORDER_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef STRATEGY_MQH - case COND_TYPE_STRATEGY: - if (Object::IsValid(_entry.obj)) { - _result = ((Strategy *)_entry.obj).CheckCondition((ENUM_STRATEGY_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif -#ifdef TASK_MQH - case COND_TYPE_TASK: - if (Object::IsValid(_entry.obj)) { - _result = ((Task *)_entry.obj).CheckCondition((ENUM_TASK_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - case COND_TYPE_TRADE: - if (Object::IsValid(_entry.obj)) { - _result = ((Trade *)_entry.obj).CheckCondition((ENUM_TRADE_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#ifdef TERMINAL_MQH - case COND_TYPE_TERMINAL: - if (Object::IsValid(_entry.obj)) { - _result = ((Terminal *)_entry.obj).CheckCondition((ENUM_TERMINAL_CONDITION)_entry.cond_id, _entry.args); - } else { - _result = false; - _entry.AddFlags(COND_ENTRY_FLAG_IS_INVALID); - } - break; -#endif - } + bool Check() { + bool _result = entry.IsValid() && entry.HasTriesLeft(); + _result &= obj.Check(entry); if (_result) { - _entry.last_success = TimeCurrent(); - _entry.tries--; + entry.RemoveFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); + entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_CHECK), TimeCurrent()); + entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS), TimeCurrent()); + } else { + entry.AddFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID)); + entry.RemoveFlags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); + entry.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_TIME_LAST_CHECK), TimeCurrent()); } - _entry.last_check = TimeCurrent(); + entry.TriesDec(); return _result; } - /* Other methods */ + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + // @todo + return false; + } /* Getters */ /** - * Returns conditions. + * Gets an entry's flag. */ - DictStruct *GetConditions() { return &conds; } + bool Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag) const { return entry.Get(_flag); } + + /** + * Gets an entry's property value. + */ + template + T Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop) const { + entry.Get(_prop); + } + + /** + * Gets a reference to the object. + */ + TC *GetObject() { return GetPointer(obj); } /* Setters */ + + /** + * Sets an entry's flag. + */ + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { + entry.Set(_flag, _value); + } + + /** + * Sets an entry's property value. + */ + template + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); + } }; -#endif // TASK_CONDITION_MQH +#endif // TASK_CONDITION_H diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 97b10383e..582d12e0d 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -42,36 +42,115 @@ #include "Task.enum.h" struct TaskConditionEntry { + public: + /* Enumerations */ + + // Defines condition entry properties. + enum ENUM_TASK_CONDITION_ENTRY_PROP { + TASK_CONDITION_ENTRY_FLAGS, + TASK_CONDITION_ENTRY_FREQUENCY, + TASK_CONDITION_ENTRY_ID, + TASK_CONDITION_ENTRY_TRIES, + TASK_CONDITION_ENTRY_TIME_LAST_CHECK, + TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS, + }; + + // Defines condition entry flags.. + enum ENUM_TASK_CONDITION_ENTRY_FLAGS { + TASK_CONDITION_ENTRY_FLAG_NONE = 0 << 0, + TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_CONDITION_ENTRY_FLAG_IS_EXPIRED = 1 << 1, + TASK_CONDITION_ENTRY_FLAG_IS_INVALID = 1 << 2, + TASK_CONDITION_ENTRY_FLAG_IS_READY = 1 << 3, + }; + + protected: unsigned char flags; // Condition flags. datetime last_check; // Time of the latest check. datetime last_success; // Time of the last success. - int frequency; // How often to check. - long cond_id; // Condition ID. + int freq; // How often to run (0 for no limit). + long id; // Condition ID. short tries; // Number of successful tries left. - void *obj; // Reference to associated object. ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. ENUM_TASK_CONDITION_TYPE type; // Task's condition type. DataParamEntry args[]; // Task's condition arguments. + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + + public: // Constructors. - void TaskConditionEntry() : type(FINAL_CONDITION_TYPE_ENTRY), cond_id(WRONG_VALUE) { Init(); } - void TaskConditionEntry(long _cond_id, ENUM_TASK_CONDITION_TYPE _type) : type(_type), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(TaskConditionEntry &_ce) { this = _ce; } - void TaskConditionEntry(ENUM_ACCOUNT_CONDITION _cond_id) : type(COND_TYPE_ACCOUNT), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_CHART_CONDITION _cond_id) : type(COND_TYPE_CHART), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_DATETIME_CONDITION _cond_id) : type(COND_TYPE_DATETIME), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_EA_CONDITION _cond_id) : type(COND_TYPE_EA), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_INDICATOR_CONDITION _cond_id) : type(COND_TYPE_INDICATOR), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_MARKET_CONDITION _cond_id) : type(COND_TYPE_MARKET), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_ORDER_CONDITION _cond_id) : type(COND_TYPE_ORDER), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_STRATEGY_CONDITION _cond_id) : type(COND_TYPE_STRATEGY), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_TASK_CONDITION _cond_id) : type(COND_TYPE_TASK), cond_id(_cond_id) { Init(); } - void TaskConditionEntry(ENUM_TRADE_CONDITION _cond_id) : type(COND_TYPE_TRADE), cond_id(_cond_id) { Init(); } + TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(0) { Init(); } + TaskConditionEntry(long _id) + : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), + freq(60), + id(_id), + last_check(0), + last_success(0), + tries(0) { + Init(); + } + TaskConditionEntry(TaskConditionEntry &_ae) { this = _ae; } // Deconstructor. - void ~TaskConditionEntry() { - // Object::Delete(obj); + void ~TaskConditionEntry() {} + // Getters. + bool Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_CONDITION_ENTRY_FLAGS: + return (T)flags; + case TASK_CONDITION_ENTRY_FREQUENCY: + return (T)freq; + case TASK_CONDITION_ENTRY_ID: + return (T)id; + case TASK_CONDITION_ENTRY_TRIES: + return (T)tries; + case TASK_CONDITION_ENTRY_TIME_LAST_CHECK: + return (T)last_check; + case TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS: + return (T)last_success; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + long GetId() const { return id; } + // Setters. + void TriesDec() { tries--; } + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_CONDITION_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_CONDITION_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_CONDITION_ENTRY_ID: + id = (long)_value; + SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_CONDITION_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_CONDITION_ENTRY_TIME_LAST_CHECK: + last_check = (datetime)_value; + return; + case TASK_CONDITION_ENTRY_TIME_LAST_SUCCESS: + last_success = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); } // Flag methods. - bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } void SetFlag(ENUM_TASK_CONDITION_ENTRY_FLAGS _flag, bool _value) { @@ -82,30 +161,19 @@ struct TaskConditionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool IsActive() { return HasFlag(COND_ENTRY_FLAG_IS_ACTIVE); } - bool IsExpired() { return HasFlag(COND_ENTRY_FLAG_IS_EXPIRED); } - bool IsReady() { return HasFlag(COND_ENTRY_FLAG_IS_READY); } - bool IsInvalid() { return HasFlag(COND_ENTRY_FLAG_IS_INVALID); } - bool IsValid() { return !IsInvalid(); } - // Getters. - long GetId() { return cond_id; } - ENUM_TASK_CONDITION_TYPE GetType() { return type; } + bool HasTriesLeft() const { return tries > 0; } + bool IsActive() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE); } + bool IsExpired() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_EXPIRED); } + bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } + bool IsInvalid() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_INVALID); } + bool IsValid() const { return !IsInvalid(); } + ENUM_TASK_CONDITION_TYPE GetType() const { return type; } // Setters. void AddArg(MqlParam &_arg) { // @todo: Add another value to args[]. } - void Init() { - flags = COND_ENTRY_FLAG_NONE; - frequency = 60; - SetFlag(COND_ENTRY_FLAG_IS_ACTIVE, cond_id != WRONG_VALUE); - SetFlag(COND_ENTRY_FLAG_IS_INVALID, cond_id == WRONG_VALUE); - last_check = last_success = 0; - next_statement = COND_AND; - tries = 1; - } void SetArgs(MqlParam &_args[]) { // @todo: for(). } - void SetObject(void *_obj) { obj = _obj; } void SetTries(short _count) { tries = _count; } }; diff --git a/Task/TaskConditionBase.h b/Task/TaskConditionBase.h new file mode 100644 index 000000000..c2cf52cbf --- /dev/null +++ b/Task/TaskConditionBase.h @@ -0,0 +1,57 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides a base class for a task's action. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_CONDITION_BASE_H +#define TASK_CONDITION_BASE_H + +/** + * TaskConditionBase class. + */ +class TaskConditionBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskConditionBase() {} + + /* Main methods */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) = NULL; +}; + +#endif // TASK_CONDITION_BASE_H diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index fd2d006f9..71a4a6446 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -24,172 +24,69 @@ * Test functionality of TaskCondition class. */ -// Forward declaration. -struct DataParamEntry; - // Includes. #include "../../DictObject.mqh" -#include "../../Indicators/Indi_Demo.mqh" -#include "../../Test.mqh" #include "../TaskCondition.h" - -// Global variables. -Chart *chart; -DictObject conds; -int bar_processed; +#include "../TaskConditionBase.h" + +enum ENUM_TASK_CONDITION_TEST { + TASK_CONDITION_TEST01 = 1, + TASK_CONDITION_TEST02 = 2, + TASK_CONDITION_TEST03 = 3, +}; + +class TaskConditionTest01 : public TaskConditionBase { + protected: + long sum; + + public: + TaskConditionTest01() : sum(0){}; + long GetSum() { return sum; } + bool Check(const TaskConditionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + return true; + } +}; + +class TaskConditionTest02 : public TaskConditionBase { + protected: + long sum; + + public: + TaskConditionTest02() : sum(0){}; + long GetSum() { return sum; } + bool Check(const TaskConditionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + return true; + } +}; /** * Implements Init event handler. */ int OnInit() { bool _result = true; - bar_processed = 0; - chart = new Chart(PERIOD_M1); - _result &= TestAccountConditions(); - _result &= TestChartConditions(); - _result &= TestDateTimeConditions(); - _result &= TestIndicatorConditions(); - _result &= TestMarketConditions(); - _result &= TestMathConditions(); - _result &= TestOrderConditions(); - _result &= TestTradeConditions(); + // Test01 + TaskConditionEntry _entry01(TASK_CONDITION_TEST01); + TaskCondition _cond01(_entry01); + _cond01.Check(); + //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); + _cond01.Check(); + //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); + _cond01.Check(); + // assertTrueOrFail(_cond01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; - return _result ? INIT_SUCCEEDED : INIT_FAILED; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); } /** * Implements Tick event handler. */ -void OnTick() { - if (chart.IsNewBar()) { - // ... - bar_processed++; - } -} +void OnTick() {} /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { delete chart; } - -/** - * Test account conditions. - */ -bool TestAccountConditions() { - bool _result = true; - Account *_acc = new Account(); - TaskCondition *_cond = new TaskCondition(ACCOUNT_COND_BAL_IN_LOSS); - assertTrueOrReturnFalse(_cond.Test() == _acc.CheckCondition(ACCOUNT_COND_BAL_IN_LOSS), - "Wrong condition: ACCOUNT_COND_BAL_IN_LOSS!"); - delete _cond; - delete _acc; - return _result; -} - -/** - * Test chart conditions. - */ -bool TestChartConditions() { - bool _result = true; - Chart *_chart = new Chart(); - TaskCondition *_cond = new TaskCondition(CHART_COND_ASK_BAR_PEAK, _chart); - assertTrueOrReturnFalse(_cond.Test() == _chart.CheckCondition(CHART_COND_ASK_BAR_PEAK), - "Wrong condition: CHART_COND_ASK_BAR_PEAK!"); - delete _cond; - delete _chart; - return _result; -} - -/** - * Test date time conditions. - */ -bool TestDateTimeConditions() { - bool _result = true; - DateTime *_dt = new DateTime(); - TaskCondition *_cond1 = new TaskCondition(DATETIME_COND_NEW_HOUR, _dt); - assertTrueOrReturnFalse(_cond1.Test() == _dt.CheckCondition(DATETIME_COND_NEW_HOUR), - "Wrong condition: DATETIME_COND_NEW_HOUR (dynamic)!"); - delete _cond1; - TaskCondition *_cond2 = new TaskCondition(DATETIME_COND_NEW_HOUR); - assertTrueOrReturnFalse(_cond2.Test() == DateTime::CheckCondition(DATETIME_COND_NEW_HOUR), - "Wrong condition: DATETIME_COND_NEW_HOUR (static)!"); - delete _cond2; - delete _dt; - return _result; -} - -/** - * Test indicator conditions. - */ -bool TestIndicatorConditions() { - bool _result = true; - Indi_Demo *_demo = new Indi_Demo(); - /* @fixme - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_IS_MAX, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MAX), - "Wrong condition: INDI_COND_ENTRY_IS_MAX!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_IS_MIN, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_IS_MIN), - "Wrong condition: INDI_COND_ENTRY_IS_MIN!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_GT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_AVG), - "Wrong condition: INDI_COND_ENTRY_GT_AVG!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_GT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_GT_MED), - "Wrong condition: INDI_COND_ENTRY_GT_MED!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_LT_AVG, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_AVG), - "Wrong condition: INDI_COND_ENTRY_LT_AVG!"); - assertTrueOrReturnFalse( - (new TaskCondition(INDI_COND_ENTRY_LT_MED, _demo)).Test() == _demo.CheckCondition(INDI_COND_ENTRY_LT_MED), - "Wrong condition: INDI_COND_ENTRY_LT_MED!"); - */ - delete _demo; - return _result; -} - -/** - * Test market conditions. - */ -bool TestMarketConditions() { - bool _result = true; - Market *_market = new Market(); - TaskCondition *_cond = new TaskCondition(MARKET_COND_IN_PEAK_HOURS, _market); - assertTrueOrReturnFalse(_cond.Test() == _market.CheckCondition(MARKET_COND_IN_PEAK_HOURS), - "Wrong condition: MARKET_COND_IN_PEAK_HOURS!"); - delete _cond; - delete _market; - return _result; -} - -/** - * Test math conditions. - */ -bool TestMathConditions() { - bool _result = true; - // @todo - return _result; -} - -/** - * Test order conditions. - */ -bool TestOrderConditions() { - bool _result = true; - // @todo - return _result; -} - -/** - * Test trade conditions. - */ -bool TestTradeConditions() { - bool _result = true; - Trade *_trade = new Trade(); - TaskCondition *_cond = new TaskCondition(TRADE_COND_ALLOWED_NOT, _trade); - assertTrueOrReturnFalse(_cond.Test() == _trade.CheckCondition(TRADE_COND_ALLOWED_NOT), - "Wrong condition: TRADE_COND_ALLOWED_NOT!"); - delete _cond; - delete _trade; - return _result; -} +void OnDeinit(const int reason) {} From 39120fafd59f65608bab4629d83d92c01a26dc0e Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 24 Oct 2021 21:19:33 +0100 Subject: [PATCH 35/97] GHA: Disables 3DTest --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fca2896d8..a9b127cf1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -97,7 +97,7 @@ jobs: strategy: matrix: test: - - 3DTest + # - 3DTest - CollectionTest - ConfigTest - ConvertTest From d37cd3184397cbbe84c2cf7155ea486332222db9 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 21:27:11 +0100 Subject: [PATCH 36/97] TaskCondition: Code test fixes --- Task/TaskAction.struct.h | 10 +++++----- Task/TaskCondition.h | 11 ++--------- Task/TaskCondition.struct.h | 21 +++++++-------------- Task/tests/TaskAction.test.mq5 | 2 +- Task/tests/TaskCondition.test.mq5 | 14 +++++++------- 5 files changed, 22 insertions(+), 36 deletions(-) diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 2518789f8..4d2d38ce9 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -61,7 +61,7 @@ struct TaskActionEntry { datetime time_last_run; /* Time of the successful run. */ int freq; /* How often to run (0 for no limit). */ long id; /* TaskAction's enum ID. */ - short tries; /* Number of retries left. */ + short tries; /* Number of retries left (-1 for unlimited). */ DataParamEntry args[]; /* TaskAction arguments. */ protected: // Protected methods. @@ -69,13 +69,13 @@ struct TaskActionEntry { public: // Constructors. - TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(0) { Init(); } + TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(-1) { Init(); } TaskActionEntry(long _id) : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), freq(60), time_last_run(0), - tries(0) { + tries(-1) { Init(); } TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } @@ -92,7 +92,7 @@ struct TaskActionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool HasTriesLeft() const { return tries > 0; } + bool HasTriesLeft() const { return tries > 0 || tries == -1; } bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); } bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED)); } @@ -121,7 +121,7 @@ struct TaskActionEntry { } long GetId() const { return id; } // Setters. - void TriesDec() { tries--; } + void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { SetFlag(_flag, _value); } diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index b51028f59..17bfa086d 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -35,15 +35,8 @@ #define TASK_CONDITION_H // Includes. -#include "../Account.mqh" -#include "../Chart.mqh" -#include "../DateTime.mqh" -#include "../DictStruct.mqh" -#include "../EA.mqh" -#include "../Indicator.mqh" -#include "../Market.mqh" -#include "../Object.mqh" -#include "../Order.mqh" +#include "TaskCondition.enum.h" +#include "TaskCondition.struct.h" // Includes class enum and structs. #include "TaskCondition.enum.h" diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 582d12e0d..b56e7e112 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -30,15 +30,8 @@ #endif // Includes. -#include "../Account.enum.h" -#include "../Chart.enum.h" -#include "../DateTime.enum.h" -#include "../EA.enum.h" -#include "../Indicator.enum.h" -//#include "Market.enum.h" -#include "../Order.enum.h" -#include "../Strategy.enum.h" -#include "../Trade.enum.h" +#include "../Data.struct.h" +#include "../Std.h" #include "Task.enum.h" struct TaskConditionEntry { @@ -70,7 +63,7 @@ struct TaskConditionEntry { datetime last_success; // Time of the last success. int freq; // How often to run (0 for no limit). long id; // Condition ID. - short tries; // Number of successful tries left. + short tries; // Number of successful tries left (-1 for unlimited). ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. ENUM_TASK_CONDITION_TYPE type; // Task's condition type. DataParamEntry args[]; // Task's condition arguments. @@ -80,14 +73,14 @@ struct TaskConditionEntry { public: // Constructors. - TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(0) { Init(); } + TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(-1) { Init(); } TaskConditionEntry(long _id) : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), freq(60), id(_id), last_check(0), last_success(0), - tries(0) { + tries(-1) { Init(); } TaskConditionEntry(TaskConditionEntry &_ae) { this = _ae; } @@ -118,7 +111,7 @@ struct TaskConditionEntry { } long GetId() const { return id; } // Setters. - void TriesDec() { tries--; } + void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { SetFlag(_flag, _value); } @@ -161,7 +154,7 @@ struct TaskConditionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - bool HasTriesLeft() const { return tries > 0; } + bool HasTriesLeft() const { return tries > 0 || tries == -1; } bool IsActive() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE); } bool IsExpired() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_EXPIRED); } bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 3b7d3dec5..6db57f164 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -76,7 +76,7 @@ int OnInit() { _action01.Run(); _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); _action01.Run(); - assertTrueOrFail(_action01.GetObject().GetSum() == 6, "Fail!"); + assertTrueOrFail(_result && _action01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index 71a4a6446..e565a5fc3 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -25,7 +25,7 @@ */ // Includes. -#include "../../DictObject.mqh" +#include "../../Test.mqh" #include "../TaskCondition.h" #include "../TaskConditionBase.h" @@ -71,12 +71,12 @@ int OnInit() { // Test01 TaskConditionEntry _entry01(TASK_CONDITION_TEST01); TaskCondition _cond01(_entry01); - _cond01.Check(); - //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); - _cond01.Check(); - //_cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); - _cond01.Check(); - // assertTrueOrFail(_cond01.GetObject().GetSum() == 6, "Fail!"); + _result &= _cond01.Check(); + _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); + _result &= _cond01.Check(); + _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); + _result &= _cond01.Check(); + assertTrueOrFail(_result && _cond01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 12dbb363d73cfc2068b63d88ca7adc745b979afb Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 22:11:36 +0100 Subject: [PATCH 37/97] Task: Code cleanup --- Task/Task.h | 9 +--- Task/Task.struct.h | 21 +++++----- Task/TaskAction.h | 3 +- Task/TaskAction.struct.h | 2 +- Task/TaskCondition.h | 7 +--- Task/TaskCondition.struct.h | 21 +++++----- Task/TaskConditionBase.h | 2 +- Task/tests/Task.test.mq5 | 69 ++----------------------------- Task/tests/TaskAction.test.mq5 | 1 - Task/tests/TaskCondition.test.mq5 | 1 - 10 files changed, 31 insertions(+), 105 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index d6a718f02..dfd7eaf9c 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -43,10 +43,6 @@ #include "TaskCondition.h" class Task { - protected: - // Class variables. - Ref logger; - public: // Class variables. DictStruct tasks; @@ -69,8 +65,6 @@ class Task { */ ~Task() {} - Log *Logger() { return logger.Ptr(); } - /* Main methods */ /** @@ -239,7 +233,6 @@ class Task { // Is invalid. return IsInvalid(); default: - Logger().Error(StringFormat("Invalid Task condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); return false; } } @@ -263,7 +256,7 @@ class Task { // Process tasks. return Process(); default: - Logger().Error(StringFormat("Invalid Task action: %s!", EnumToString(_action), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); return false; } return _result; diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 82e7b6684..5d8061c62 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -36,12 +36,23 @@ #include "TaskCondition.struct.h" struct TaskEntry { + protected: TaskActionEntry action; // TaskAction of the task. TaskConditionEntry cond; // TaskCondition of the task. datetime expires; // Time of expiration. datetime last_process; // Time of the last process. datetime last_success; // Time of the last success. unsigned char flags; // TaskAction flags. + protected: + // Protected methods. + void Init() { + flags = TASK_ENTRY_FLAG_NONE; + SetFlag(TASK_ENTRY_FLAG_IS_ACTIVE, action.IsActive() && cond.IsActive()); + SetFlag(TASK_ENTRY_FLAG_IS_INVALID, action.IsInvalid() || cond.IsInvalid()); + expires = last_process = last_success = 0; + } + + public: // Constructors. void TaskEntry() { Init(); } void TaskEntry(TaskActionEntry &_action, TaskConditionEntry &_cond) : action(_action), cond(_cond) { Init(); } @@ -49,13 +60,6 @@ struct TaskEntry { void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { Init(); }; - // Main methods. - void Init() { - flags = TASK_ENTRY_FLAG_NONE; - SetFlag(TASK_ENTRY_FLAG_IS_ACTIVE, action.IsActive() && cond.IsActive()); - SetFlag(TASK_ENTRY_FLAG_IS_INVALID, action.IsInvalid() || cond.IsInvalid()); - expires = last_process = last_success = 0; - } // Flag methods. bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -77,7 +81,4 @@ struct TaskEntry { long GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } - // Setters. - // void SetActionObject(void *_obj) { action.SetObject(_obj); } - // void SetConditionObject(void *_obj) { cond.SetObject(_obj); } }; diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 56ed17fe2..bd56eb8ac 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -22,7 +22,7 @@ /** * @file - * Provides integration with actions. + * Provides integration with task's actions. */ #ifndef __MQL__ @@ -37,6 +37,7 @@ // Includes. #include "TaskAction.enum.h" #include "TaskAction.struct.h" +#include "TaskActionBase.h" /** * TaskAction class. diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 4d2d38ce9..0f251d674 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -21,7 +21,7 @@ /** * @file - * Includes TaskAction's structs. + * Includes TaskAction's structures. */ #ifndef __MQL__ diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 17bfa086d..909e244ba 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -22,7 +22,7 @@ /** * @file - * Provides integration with conditions. + * Provides integration with task's conditions. */ #ifndef __MQL__ @@ -37,10 +37,7 @@ // Includes. #include "TaskCondition.enum.h" #include "TaskCondition.struct.h" - -// Includes class enum and structs. -#include "TaskCondition.enum.h" -#include "TaskCondition.struct.h" +#include "TaskConditionBase.h" /** * TaskCondition class. diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index b56e7e112..82b0dc7ca 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -21,7 +21,7 @@ /** * @file - * Includes Condition's structs. + * Includes TaskCondition's structures. */ #ifndef __MQL__ @@ -58,15 +58,15 @@ struct TaskConditionEntry { }; protected: - unsigned char flags; // Condition flags. - datetime last_check; // Time of the latest check. - datetime last_success; // Time of the last success. - int freq; // How often to run (0 for no limit). - long id; // Condition ID. - short tries; // Number of successful tries left (-1 for unlimited). - ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. - ENUM_TASK_CONDITION_TYPE type; // Task's condition type. - DataParamEntry args[]; // Task's condition arguments. + unsigned char flags; // Condition flags. + datetime last_check; // Time of the latest check. + datetime last_success; // Time of the last success. + int freq; // How often to run (0 for no limit). + long id; // Condition ID. + short tries; // Number of successful tries left (-1 for unlimited). + // ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. + // ENUM_TASK_CONDITION_TYPE type; // Task's condition type. + DataParamEntry args[]; // Task's condition arguments. protected: // Protected methods. void Init() { SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } @@ -160,7 +160,6 @@ struct TaskConditionEntry { bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } bool IsInvalid() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_INVALID); } bool IsValid() const { return !IsInvalid(); } - ENUM_TASK_CONDITION_TYPE GetType() const { return type; } // Setters. void AddArg(MqlParam &_arg) { // @todo: Add another value to args[]. diff --git a/Task/TaskConditionBase.h b/Task/TaskConditionBase.h index c2cf52cbf..0e8e12d5b 100644 --- a/Task/TaskConditionBase.h +++ b/Task/TaskConditionBase.h @@ -22,7 +22,7 @@ /** * @file - * Provides a base class for a task's action. + * Provides a base class for a task's condition. */ #ifndef __MQL__ diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 31be5230c..623bd8d9e 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -28,50 +28,15 @@ struct DataParamEntry; // Includes. -#include "../../Chart.mqh" -#include "../../DictObject.mqh" -#include "../../EA.mqh" #include "../../Test.mqh" #include "../Task.h" -#include "../TaskAction.h" -#include "../TaskCondition.h" - -// Global variables. -Chart *chart; -EA *ea; -DictObject tasks; - -// Define strategy classes. -class Stg1 : public Strategy { - public: - void Stg1(StgParams &_params, TradeParams &_tparams, ChartParams &_cparams, string _name = "Stg1") - : Strategy(_params, _tparams, _cparams, _name) {} - static Stg1 *Init(ENUM_TIMEFRAMES _tf = NULL, unsigned long _magic_no = 0, ENUM_LOG_LEVEL _log_level = V_INFO) { - ChartParams _cparams(_tf); - TradeParams _tparams(_magic_no, _log_level); - Strategy *_strat = new Stg1(stg_params_defaults, _tparams, _cparams, __FUNCTION__); - return _strat; - } - bool SignalOpen(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - bool SignalOpenFilterMethod(ENUM_ORDER_TYPE _cmd, int _method = 0) { return true; } - float SignalOpenBoost(ENUM_ORDER_TYPE _cmd, int _method = 0) { return 1.0f; } - bool SignalClose(ENUM_ORDER_TYPE _cmd, int _method, float _level, int _shift) { return true; } - float PriceStop(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_TYPE_VALUE _mode, int _method = 0, float _level = 0.0f) { - return _level; - } -}; /** * Implements Init event handler. */ int OnInit() { bool _result = true; - // Initializes chart. - chart = new Chart(); - // Initializes EA. - EAParams ea_params(__FILE__); - ea = new EA(ea_params); - //_result &= ea.StrategyAdd(127); + // @todo _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } @@ -79,37 +44,9 @@ int OnInit() { /** * Implements Tick event handler. */ -void OnTick() { - chart.OnTick(); - if (chart.IsNewBar()) { - unsigned int _bar_index = chart.GetBarIndex(); - switch (_bar_index) { - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - break; - case 5: - break; - case 6: - break; - case 7: - break; - case 8: - break; - case 9: - break; - } - } -} +void OnTick() {} /** * Implements Deinit event handler. */ -void OnDeinit(const int reason) { - delete chart; - delete ea; -} +void OnDeinit(const int reason) {} diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 6db57f164..4b6b815df 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -27,7 +27,6 @@ // Includes. #include "../../Test.mqh" #include "../TaskAction.h" -#include "../TaskActionBase.h" enum ENUM_TASK_ACTION_TEST { TASK_ACTION_TEST01 = 1, diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index e565a5fc3..aeef3cede 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -27,7 +27,6 @@ // Includes. #include "../../Test.mqh" #include "../TaskCondition.h" -#include "../TaskConditionBase.h" enum ENUM_TASK_CONDITION_TEST { TASK_CONDITION_TEST01 = 1, From bec31a5b8b81d87c83f16ae8cba6624767cef9ac Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 22:41:56 +0100 Subject: [PATCH 38/97] Task: Adds Taskable class --- .github/workflows/test-task.yml | 1 + Task/Task.h | 3 +- Task/Taskable.h | 66 +++++++++++++++++++++++++ Task/tests/Taskable.test.mq4 | 28 +++++++++++ Task/tests/Taskable.test.mq5 | 86 +++++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 Task/Taskable.h create mode 100644 Task/tests/Taskable.test.mq4 create mode 100644 Task/tests/Taskable.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 36ed3cbf9..fa56d6cab 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -49,6 +49,7 @@ jobs: matrix: test: - Task.test + - Taskable.test - TaskAction.test - TaskCondition.test steps: diff --git a/Task/Task.h b/Task/Task.h index dfd7eaf9c..93f445f3e 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -41,8 +41,9 @@ #include "Task.struct.h" #include "TaskAction.h" #include "TaskCondition.h" +#include "Taskable.h" -class Task { +class Task : protected Taskable { public: // Class variables. DictStruct tasks; diff --git a/Task/Taskable.h b/Task/Taskable.h new file mode 100644 index 000000000..cbd9b6ebe --- /dev/null +++ b/Task/Taskable.h @@ -0,0 +1,66 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Defines Taskable class. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASKABLE_H +#define TASKABLE_H + +// Includes. +#include "TaskAction.h" +#include "TaskCondition.h" + +/** + * Taskable class. + */ +class Taskable { + public: + /* Special methods */ + + /** + * Class constructor. + */ + Taskable() {} + + /* Main methods */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) = NULL; + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) = NULL; +}; + +#endif // TASKABLE_H diff --git a/Task/tests/Taskable.test.mq4 b/Task/tests/Taskable.test.mq4 new file mode 100644 index 000000000..47e309712 --- /dev/null +++ b/Task/tests/Taskable.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Taskable class. + */ + +// Includes. +#include "Taskable.test.mq5" diff --git a/Task/tests/Taskable.test.mq5 b/Task/tests/Taskable.test.mq5 new file mode 100644 index 000000000..9bbd4519d --- /dev/null +++ b/Task/tests/Taskable.test.mq5 @@ -0,0 +1,86 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Taskable class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../Taskable.h" + +class TaskTest01 : public Taskable { + protected: + long sum; + + public: + TaskTest01() : sum(0){}; + long GetSum() { return sum; } + + /** + * Checks a condition. + */ + bool Check(const TaskConditionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + return true; + } + + /* Main methods */ + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + sum += _entry.GetId(); + PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + return true; + } +}; + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + TaskTest01 _test01; + // Checks dummy condition. + TaskConditionEntry _entry_cond(2); + _result &= _test01.Check(_entry_cond); + // Runs dummy action. + TaskActionEntry _entry_action(2); + _result &= _test01.Run(_entry_action); + // Checks the results. + assertTrueOrFail(_result && _test01.GetSum() == 4, "Fail!"); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 45e02427bdd8adf8cc5e39b6cec45353ef82bfa2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 23:14:34 +0100 Subject: [PATCH 39/97] Task: Code improvements --- Task/Task.h | 8 ++--- Task/TaskAction.h | 28 +++++++++++------ Task/TaskAction.struct.h | 8 ++--- Task/TaskCondition.h | 63 +++++++++++-------------------------- Task/TaskCondition.struct.h | 8 ++--- 5 files changed, 48 insertions(+), 67 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 93f445f3e..0fe53b3e7 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -36,7 +36,6 @@ // Includes. #include "../DictStruct.mqh" -#include "../Refs.mqh" #include "Task.enum.h" #include "Task.struct.h" #include "TaskAction.h" @@ -80,11 +79,10 @@ class Task : protected Taskable { * Returns true when tasks has been processed. */ bool Process() { - bool _result = false; + bool _result = true; for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { - bool _curr_result = false; TaskEntry _entry = iter.Value(); - Process(_entry); + _result &= Process(_entry); } return _result; } @@ -116,6 +114,8 @@ class Task : protected Taskable { return _result; } + /* Task methods */ + /* State methods */ /** diff --git a/Task/TaskAction.h b/Task/TaskAction.h index bd56eb8ac..db6c78745 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -43,7 +43,7 @@ * TaskAction class. */ template -class TaskAction : TaskActionBase { +class TaskAction : protected TaskActionBase { protected: // Protected class variables. TaskActionEntry entry; // Action entry. @@ -65,7 +65,7 @@ class TaskAction : TaskActionBase { /* Main methods */ /** - * Runs a current action. + * Runs a current stored action. */ bool Run() { bool _result = entry.IsValid() && entry.HasTriesLeft(); @@ -82,14 +82,6 @@ class TaskAction : TaskActionBase { return _result; } - /** - * Runs a TaskAction action. - */ - virtual bool Run(const TaskActionEntry &_entry) { - // @todo - return false; - } - /* Getters */ /** @@ -126,6 +118,22 @@ class TaskAction : TaskActionBase { void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop, T _value) { entry.Set(_prop, _value); } + + /* TaskActionBase methods */ + + /** + * Runs an action. + */ + bool Run(const TaskActionEntry &_entry) { + switch (_entry.GetId()) { + case 0: + return Run(); + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return false; + } }; #endif // TASK_ACTION_H diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 0f251d674..7014144c6 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -60,7 +60,7 @@ struct TaskActionEntry { unsigned char flags; /* TaskAction flags. */ datetime time_last_run; /* Time of the successful run. */ int freq; /* How often to run (0 for no limit). */ - long id; /* TaskAction's enum ID. */ + int id; /* TaskAction's enum ID. */ short tries; /* Number of retries left (-1 for unlimited). */ DataParamEntry args[]; /* TaskAction arguments. */ protected: @@ -70,7 +70,7 @@ struct TaskActionEntry { public: // Constructors. TaskActionEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_run(0), tries(-1) { Init(); } - TaskActionEntry(long _id) + TaskActionEntry(int _id) : flags(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)), id(_id), freq(60), @@ -119,7 +119,7 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - long GetId() const { return id; } + int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag, bool _value = true) { @@ -135,7 +135,7 @@ struct TaskActionEntry { freq = (int)_value; return; case TASK_ACTION_ENTRY_ID: - id = (long)_value; + id = (int)_value; SetFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); return; case TASK_ACTION_ENTRY_TRIES: diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 909e244ba..42d977754 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -43,7 +43,7 @@ * TaskCondition class. */ template -class TaskCondition { +class TaskCondition : protected TaskConditionBase { public: protected: // Protected class variables. @@ -66,42 +66,7 @@ class TaskCondition { /* Main methods */ /** - * Test conditions. - */ - /* - bool Test() { - bool _result = false, _prev_result = true; - for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) { - bool _curr_result = false; - TaskConditionEntry _entry = iter.Value(); - if (!_entry.IsValid()) { - // Ignore invalid entries. - continue; - } - if (_entry.IsActive()) { - switch (_entry.next_statement) { - case COND_AND: - _curr_result = _prev_result && this.Test(_entry); - break; - case COND_OR: - _curr_result = _prev_result || this.Test(_entry); - break; - case COND_SEQ: - _curr_result = this.Test(_entry); - if (!_curr_result) { - // Do not check further conditions when the current condition is false. - return false; - } - } - _result = _prev_result = _curr_result; - } - } - return _result; - } - */ - - /** - * Checks a current condition. + * Checks a current stored condition. */ bool Check() { bool _result = entry.IsValid() && entry.HasTriesLeft(); @@ -119,14 +84,6 @@ class TaskCondition { return _result; } - /** - * Checks a condition. - */ - virtual bool Check(const TaskConditionEntry &_entry) { - // @todo - return false; - } - /* Getters */ /** @@ -163,5 +120,21 @@ class TaskCondition { void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_PROP) _prop, T _value) { entry.Set(_prop, _value); } + + /* TaskConditionBase methods */ + + /** + * Checks a condition. + */ + bool Check(const TaskConditionEntry &_entry) { + switch (_entry.GetId()) { + case 0: + return Check(); + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return false; + } }; #endif // TASK_CONDITION_H diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 82b0dc7ca..bbd1c557e 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -62,7 +62,7 @@ struct TaskConditionEntry { datetime last_check; // Time of the latest check. datetime last_success; // Time of the last success. int freq; // How often to run (0 for no limit). - long id; // Condition ID. + int id; // Condition ID. short tries; // Number of successful tries left (-1 for unlimited). // ENUM_TASK_CONDITION_STATEMENT next_statement; // Statement type of the next condition. // ENUM_TASK_CONDITION_TYPE type; // Task's condition type. @@ -74,7 +74,7 @@ struct TaskConditionEntry { public: // Constructors. TaskConditionEntry() : flags(0), freq(60), id(WRONG_VALUE), tries(-1) { Init(); } - TaskConditionEntry(long _id) + TaskConditionEntry(int _id) : flags(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)), freq(60), id(_id), @@ -109,7 +109,7 @@ struct TaskConditionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - long GetId() const { return id; } + int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } void Set(STRUCT_ENUM(TaskConditionEntry, ENUM_TASK_CONDITION_ENTRY_FLAGS) _flag, bool _value = true) { @@ -125,7 +125,7 @@ struct TaskConditionEntry { freq = (int)_value; return; case TASK_CONDITION_ENTRY_ID: - id = (long)_value; + id = (int)_value; SetFlag(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); return; case TASK_CONDITION_ENTRY_TRIES: From b086fd9abecc28f45062215b619b431103f1e655 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 26 Oct 2021 23:59:29 +0100 Subject: [PATCH 40/97] Task: Adds TaskGetter class --- .github/workflows/test-task.yml | 1 + Task/TaskCondition.h | 6 +- Task/TaskGetter.h | 133 +++++++++++++++++++++++++ Task/TaskGetter.struct.h | 170 ++++++++++++++++++++++++++++++++ Task/TaskGetterBase.h | 58 +++++++++++ Task/tests/TaskGetter.test.mq4 | 28 ++++++ Task/tests/TaskGetter.test.mq5 | 86 ++++++++++++++++ 7 files changed, 479 insertions(+), 3 deletions(-) create mode 100644 Task/TaskGetter.h create mode 100644 Task/TaskGetter.struct.h create mode 100644 Task/TaskGetterBase.h create mode 100644 Task/tests/TaskGetter.test.mq4 create mode 100644 Task/tests/TaskGetter.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index fa56d6cab..d5869346f 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -52,6 +52,7 @@ jobs: - Taskable.test - TaskAction.test - TaskCondition.test + - TaskGetter.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 42d977754..21670e684 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -42,13 +42,13 @@ /** * TaskCondition class. */ -template +template class TaskCondition : protected TaskConditionBase { public: protected: // Protected class variables. TaskConditionEntry entry; // Condition entry. - TC obj; // Object to run the action on. + TO obj; // Object to run the action on. public: /* Special methods */ @@ -102,7 +102,7 @@ class TaskCondition : protected TaskConditionBase { /** * Gets a reference to the object. */ - TC *GetObject() { return GetPointer(obj); } + TO *GetObject() { return GetPointer(obj); } /* Setters */ diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h new file mode 100644 index 000000000..b25ac67f1 --- /dev/null +++ b/Task/TaskGetter.h @@ -0,0 +1,133 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides integration with task's actions. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_GETTER_H +#define TASK_GETTER_H + +// Includes. +//#include "TaskGetter.enum.h" +#include "TaskGetter.struct.h" +#include "TaskGetterBase.h" + +/** + * TaskGetter class. + */ +template +class TaskGetter : protected TaskGetterBase { + protected: + // Protected class variables. + TaskGetterEntry entry; // Getter entry. + TO obj; // Object to run the action on. + + public: + /* Special methods */ + + /** + * Default class constructor. + */ + TaskGetter() {} + + /** + * Class constructor with an entry as argument. + */ + TaskGetter(TaskGetterEntry &_entry) : entry(_entry) {} + + /* Main methods */ + + /** + * Runs a current stored action. + */ + TS Get() { + TS _result = obj.Get(entry); + entry.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); + entry.TriesDec(); + return _result; + } + + /* Getters */ + + /** + * Gets an entry's flag. + */ + bool Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag) const { return entry.Get(_flag); } + + /** + * Gets an entry's property value. + */ + template + T Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop) const { + entry.Get(_prop); + } + + /** + * Gets a reference to the object. + */ + TO *GetObject() { return GetPointer(obj); } + + /* Setters */ + + /** + * Sets an entry's flag. + */ + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value = true) { + entry.Set(_flag, _value); + } + + /** + * Sets an entry's property value. + */ + template + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); + } + + /* TaskGetterBase methods */ + + /** + * Runs an action. + */ + TS Get(const TaskGetterEntry &_entry) { + TS _result; + switch (_entry.GetId()) { + case 0: + _result = Get(); + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return _result; + } +}; + +#endif // TASK_GETTER_H diff --git a/Task/TaskGetter.struct.h b/Task/TaskGetter.struct.h new file mode 100644 index 000000000..2abe464da --- /dev/null +++ b/Task/TaskGetter.struct.h @@ -0,0 +1,170 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Includes TaskGetter's structures. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Data.struct.h" +#include "../Std.h" +#include "Task.enum.h" + +/* Entry for TaskGetter class. */ +struct TaskGetterEntry { + public: + /* Enumerations */ + + // Defines action entry properties. + enum ENUM_TASK_GETTER_ENTRY_PROP { + TASK_GETTER_ENTRY_FLAGS, + TASK_GETTER_ENTRY_FREQUENCY, + TASK_GETTER_ENTRY_ID, + TASK_GETTER_ENTRY_TRIES, + TASK_GETTER_ENTRY_TIME_LAST_GET, + }; + // Defines action entry flags. + enum ENUM_TASK_GETTER_ENTRY_FLAG { + TASK_GETTER_ENTRY_FLAG_NONE = 0 << 0, + TASK_GETTER_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_GETTER_ENTRY_FLAG_IS_DONE = 1 << 1, + TASK_GETTER_ENTRY_FLAG_IS_FAILED = 1 << 2, + TASK_GETTER_ENTRY_FLAG_IS_INVALID = 1 << 3, + }; + + protected: + unsigned char flags; /* TaskGetter flags. */ + datetime time_last_get; /* Time of the successful get. */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskGetter's enum ID. */ + short tries; /* Number of retries left (-1 for unlimited). */ + DataParamEntry args[]; /* TaskGetter arguments. */ + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + + public: + // Constructors. + TaskGetterEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_get(0), tries(-1) { Init(); } + TaskGetterEntry(int _id) + : flags(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)), + id(_id), + freq(60), + time_last_get(0), + tries(-1) { + Init(); + } + TaskGetterEntry(TaskGetterEntry &_ae) { this = _ae; } + // Flag methods. + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } + void AddFlags(unsigned char _flags) { flags |= _flags; } + void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void SetFlag(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value) { + if (_value) { + AddFlags(_flag); + } else { + RemoveFlags(_flag); + } + } + void SetFlags(unsigned char _flags) { flags = _flags; } + // State methods. + bool HasTriesLeft() const { return tries > 0 || tries == -1; } + bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); } + bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_DONE)); } + bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_FAILED)); } + bool IsInvalid() const { return HasFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID)); } + bool IsValid() const { return !IsInvalid(); } + // Getters. + bool Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_GETTER_ENTRY_FLAGS: + return (T)flags; + case TASK_GETTER_ENTRY_FREQUENCY: + return (T)freq; + case TASK_GETTER_ENTRY_ID: + return (T)id; + case TASK_GETTER_ENTRY_TRIES: + return (T)tries; + case TASK_GETTER_ENTRY_TIME_LAST_RUN: + return (T)time_last_run; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + int GetId() const { return id; } + // Setters. + void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_FLAG) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskGetterEntry, ENUM_TASK_GETTER_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_GETTER_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_GETTER_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_GETTER_ENTRY_ID: + id = (int)_value; + SetFlag(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_GETTER_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_GETTER_ENTRY_TIME_LAST_GET: + time_last_get = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + void AddArg(MqlParam &_arg) { + // @todo: Add another value to args[]. + } + void SetArgs(ARRAY_REF(MqlParam, _args)) { + // @todo: for(). + } + // Serializers + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_get", time_last_get); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(this, "args", args); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; +}; diff --git a/Task/TaskGetterBase.h b/Task/TaskGetterBase.h new file mode 100644 index 000000000..6c53af020 --- /dev/null +++ b/Task/TaskGetterBase.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides a base class for a task's getter. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_GETTER_BASE_H +#define TASK_GETTER_BASE_H + +/** + * TaskGetterBase class. + */ +template +class TaskGetterBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskGetterBase() {} + + /* Main methods */ + + /** + * Gets a structure. + */ + virtual TS Get(const TaskGetterEntry &_entry) = NULL; +}; + +#endif // TASK_GETTER_BASE_H diff --git a/Task/tests/TaskGetter.test.mq4 b/Task/tests/TaskGetter.test.mq4 new file mode 100644 index 000000000..688c4942e --- /dev/null +++ b/Task/tests/TaskGetter.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskGetter class. + */ + +// Includes. +#include "TaskGetter.test.mq5" diff --git a/Task/tests/TaskGetter.test.mq5 b/Task/tests/TaskGetter.test.mq5 new file mode 100644 index 000000000..05760ff6a --- /dev/null +++ b/Task/tests/TaskGetter.test.mq5 @@ -0,0 +1,86 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskGetter class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TaskGetter.h" + +enum ENUM_TASK_GETTER_TEST { + TASK_GETTER_TEST01 = 1, + TASK_GETTER_TEST02 = 2, + TASK_GETTER_TEST03 = 3, +}; + +struct TaskGetterTest01Data { + int value; + TaskGetterTest01Data() : value(0) {} + int GetValue() { return value; } + void SetValue(int _value) { value = _value; } +}; + +class TaskGetterTest01 : protected TaskGetterBase { + protected: + TaskGetterTest01Data data; + + public: + TaskGetterTest01(){}; + // long GetSum() { return sum; } + TaskGetterTest01Data Get(const TaskGetterEntry &_entry) { + data.SetValue(_entry.GetId()); + PrintFormat("Get: %s; value=%d", __FUNCSIG__, data.GetValue()); + return data; + } +}; + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + int _sum = 0; + // Test01 + TaskGetterEntry _entry01(TASK_GETTER_TEST01); + TaskGetter _getter01(_entry01); + _result &= _getter01.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); + _sum += _getter01.Get().GetValue(); + _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST02); + _sum += _getter01.Get().GetValue(); + _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST03); + _sum += _getter01.Get().GetValue(); + assertTrueOrFail(_result && _sum == 6, "Fail!"); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From d3b891615600e074c9a7b08d746b227571e61935 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 11:23:03 +0100 Subject: [PATCH 41/97] Task: TaskGetter: Improves tests --- Task/Task.h | 2 +- Task/TaskGetterBase.h | 2 +- Task/Taskable.h | 9 ++++- Task/tests/TaskAction.test.mq5 | 4 +-- Task/tests/TaskCondition.test.mq5 | 4 +-- Task/tests/Taskable.test.mq5 | 55 +++++++++++++++++++++++-------- 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 0fe53b3e7..5d0864b3b 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -42,7 +42,7 @@ #include "TaskCondition.h" #include "Taskable.h" -class Task : protected Taskable { +class Task : protected Taskable { public: // Class variables. DictStruct tasks; diff --git a/Task/TaskGetterBase.h b/Task/TaskGetterBase.h index 6c53af020..6261d2ce6 100644 --- a/Task/TaskGetterBase.h +++ b/Task/TaskGetterBase.h @@ -50,7 +50,7 @@ class TaskGetterBase { /* Main methods */ /** - * Gets a structure. + * Gets a copy of structure. */ virtual TS Get(const TaskGetterEntry &_entry) = NULL; }; diff --git a/Task/Taskable.h b/Task/Taskable.h index cbd9b6ebe..88345b0ee 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -37,10 +37,12 @@ // Includes. #include "TaskAction.h" #include "TaskCondition.h" +#include "TaskGetter.h" /** * Taskable class. */ +template class Taskable { public: /* Special methods */ @@ -50,13 +52,18 @@ class Taskable { */ Taskable() {} - /* Main methods */ + /* Virtual methods */ /** * Checks a condition. */ virtual bool Check(const TaskConditionEntry &_entry) = NULL; + /** + * Gets a copy of structure. + */ + virtual TS Get(const TaskGetterEntry &_entry) = NULL; + /** * Runs an action. */ diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index 4b6b815df..f1f0721af 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -43,7 +43,7 @@ class TaskActionTest01 : public TaskActionBase { long GetSum() { return sum; } bool Run(const TaskActionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; @@ -57,7 +57,7 @@ class TaskActionTest02 : public TaskActionBase { long GetSum() { return sum; } bool Run(const TaskActionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index aeef3cede..ad8f241b0 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -43,7 +43,7 @@ class TaskConditionTest01 : public TaskConditionBase { long GetSum() { return sum; } bool Check(const TaskConditionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; @@ -57,7 +57,7 @@ class TaskConditionTest02 : public TaskConditionBase { long GetSum() { return sum; } bool Check(const TaskConditionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return true; } }; diff --git a/Task/tests/Taskable.test.mq5 b/Task/tests/Taskable.test.mq5 index 9bbd4519d..38160113a 100644 --- a/Task/tests/Taskable.test.mq5 +++ b/Task/tests/Taskable.test.mq5 @@ -28,32 +28,53 @@ #include "../../Test.mqh" #include "../Taskable.h" -class TaskTest01 : public Taskable { +// Defines structure. +struct TaskableIntValue { protected: - long sum; + int value; // Field to store a double type. + public: + TaskableIntValue() : value(0) {} + void SetValue(int _value) { value = _value; } +}; + +// Defines class. +class TaskTest01 : public Taskable { + protected: + int sum; + TaskableIntValue data; public: TaskTest01() : sum(0){}; - long GetSum() { return sum; } + int GetSum() { return sum; } + + /* Taskable methods */ /** * Checks a condition. */ bool Check(const TaskConditionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Checks: %s; sum=%d", __FUNCSIG__, sum); - return true; + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); + return sum > 0; } - /* Main methods */ + /** + * Gets a copy of structure. + */ + TaskableIntValue Get(const TaskGetterEntry &_entry) { + sum += _entry.GetId(); + data.SetValue(sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); + return data; + } /** * Runs an action. */ - virtual bool Run(const TaskActionEntry &_entry) { + bool Run(const TaskActionEntry &_entry) { sum += _entry.GetId(); - PrintFormat("Runs: %s; sum=%d", __FUNCSIG__, sum); - return true; + PrintFormat("%s; sum=%d", __FUNCSIG__, sum); + return sum > 0; } }; @@ -63,14 +84,20 @@ class TaskTest01 : public Taskable { int OnInit() { bool _result = true; TaskTest01 _test01; - // Checks dummy condition. - TaskConditionEntry _entry_cond(2); - _result &= _test01.Check(_entry_cond); - // Runs dummy action. + // Runs a dummy action. TaskActionEntry _entry_action(2); _result &= _test01.Run(_entry_action); + _result &= _entry_action.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); + // Checks a dummy condition. + TaskConditionEntry _entry_cond(2); + _result &= _test01.Check(_entry_cond); + _result &= _entry_cond.Get(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_FLAG_IS_ACTIVE)); + // Gets a dummy value. + TaskGetterEntry _entry_get(2); + TaskableIntValue _value = _test01.Get(_entry_get); + _result &= _entry_get.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); // Checks the results. - assertTrueOrFail(_result && _test01.GetSum() == 4, "Fail!"); + assertTrueOrFail(_result && _test01.GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From b4b53f44499d57f390c41721ca1977192efce8eb Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 19:23:42 +0100 Subject: [PATCH 42/97] Indicators: Data types handling refactor [WIP] --- Indicator.enum.h | 13 ++-- Indicator.mqh | 100 +++++++++++++++++++++++----- Indicator.struct.h | 49 +++++++++----- Indicator.struct.serialize.h | 59 +++++++++------- Indicators/Bitwise/Indi_Pattern.mqh | 8 +-- Indicators/Indi_Drawer.mqh | 2 +- Indicators/Indi_Killzones.mqh | 24 ------- Indicators/Indi_PriceFeeder.mqh | 19 ------ Indicators/indicators.h | 1 + 9 files changed, 164 insertions(+), 111 deletions(-) diff --git a/Indicator.enum.h b/Indicator.enum.h index 1587ce083..884f705a4 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -218,12 +218,11 @@ enum ENUM_APPLIED_VOLUME { VOLUME_TICK = 0, VOLUME_REAL = 1 }; enum INDICATOR_ENTRY_FLAGS { INDI_ENTRY_FLAG_NONE = 0 << 0, INDI_ENTRY_FLAG_IS_BITWISE = 1 << 0, - INDI_ENTRY_FLAG_IS_DOUBLE = 1 << 1, + INDI_ENTRY_FLAG_IS_DOUBLED = 1 << 1, // Type is doubled in size (e.g. double or long). INDI_ENTRY_FLAG_IS_EXPIRED = 1 << 2, - INDI_ENTRY_FLAG_IS_FLOAT = 1 << 3, - INDI_ENTRY_FLAG_IS_INT = 1 << 4, - INDI_ENTRY_FLAG_IS_LONG = 1 << 5, - INDI_ENTRY_FLAG_IS_PRICE = 1 << 6, - INDI_ENTRY_FLAG_IS_VALID = 1 << 7, - INDI_ENTRY_FLAG_INSUFFICIENT_DATA = 1 << 8, // Entry has missing value for that shift and probably won't ever have. + INDI_ENTRY_FLAG_IS_REAL = 1 << 3, // Type is real (float or double). + INDI_ENTRY_FLAG_IS_PRICE = 1 << 4, + INDI_ENTRY_FLAG_IS_UNSIGNED = 1 << 5, // Type is unsigned (uint or ulong). + INDI_ENTRY_FLAG_IS_VALID = 1 << 6, + INDI_ENTRY_FLAG_INSUFFICIENT_DATA = 1 << 7, // Entry has missing value for that shift and probably won't ever have. }; diff --git a/Indicator.mqh b/Indicator.mqh index 9d82faf4a..c99900b95 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -884,15 +884,32 @@ class Indicator : public IndicatorBase { bool _result = true; _result &= _entry.timestamp > 0; _result &= _entry.GetSize() > 0; - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLE)) { - _result &= !_entry.HasValue(DBL_MAX); - _result &= !_entry.HasValue(NULL); - } else if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_FLOAT)) { - _result &= !_entry.HasValue(FLT_MAX); - _result &= !_entry.HasValue(NULL); - } else if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_INT)) { - _result &= !_entry.HasValue(INT_MAX); - _result &= !_entry.HasValue(NULL); + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(DBL_MAX); + _result &= !_entry.HasValue(NULL); + } else { + _result &= !_entry.HasValue(FLT_MAX); + _result &= !_entry.HasValue(NULL); + } + } else { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(ULONG_MAX); + _result &= !_entry.HasValue(NULL); + } else { + _result &= !_entry.HasValue(UINT_MAX); + _result &= !_entry.HasValue(NULL); + } + } else { + if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + _result &= !_entry.HasValue(LONG_MAX); + _result &= !_entry.HasValue(NULL); + } else { + _result &= !_entry.HasValue(INT_MAX); + _result &= !_entry.HasValue(NULL); + } + } } return _result; } @@ -922,7 +939,34 @@ class Indicator : public IndicatorBase { _entry.Resize(iparams.GetMaxModes()); _entry.timestamp = GetBarTime(_ishift); for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) { - _entry.values[_mode] = GetValue(_mode, _ishift); + switch (iparams.GetDataValueType()) { + case TYPE_BOOL: + case TYPE_CHAR: + case TYPE_INT: + _entry.values[_mode] = GetValue(_mode, _ishift); + break; + case TYPE_LONG: + _entry.values[_mode] = GetValue(_mode, _ishift); + break; + case TYPE_UINT: + _entry.values[_mode] = GetValue(_mode, _ishift); + break; + case TYPE_ULONG: + _entry.values[_mode] = GetValue(_mode, _ishift); + break; + case TYPE_DOUBLE: + _entry.values[_mode] = GetValue(_mode, _ishift); + break; + case TYPE_FLOAT: + _entry.values[_mode] = GetValue(_mode, _ishift); + break; + case TYPE_STRING: + case TYPE_UCHAR: + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + _entry.values[_mode] = GetValue(_mode, _ishift); } GetEntryAlter(_entry, _ishift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); @@ -948,7 +992,7 @@ class Indicator : public IndicatorBase { * This method is called on GetEntry() right after values are set. */ virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) { - _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); + _entry.AddFlags(_entry.GetDataTypeFlags(iparams.GetDataValueType())); }; /** @@ -962,12 +1006,32 @@ class Indicator : public IndicatorBase { virtual DataParamEntry GetEntryValue(int _shift = -1, int _mode = 0) { IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift()); DataParamEntry _value_entry; - if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLE)) { - _value_entry = _entry.GetValue(_mode); - } else if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_FLOAT)) { - _value_entry = _entry.GetValue(_mode); - } else if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_INT)) { - _value_entry = _entry.GetValue(_mode); + switch (iparams.GetDataValueType()) { + case TYPE_BOOL: + case TYPE_CHAR: + case TYPE_INT: + _value_entry = _entry.GetValue(_mode); + break; + case TYPE_LONG: + _value_entry = _entry.GetValue(_mode); + break; + case TYPE_UINT: + _value_entry = _entry.GetValue(_mode); + break; + case TYPE_ULONG: + _value_entry = _entry.GetValue(_mode); + break; + case TYPE_DOUBLE: + _value_entry = _entry.GetValue(_mode); + break; + case TYPE_FLOAT: + _value_entry = _entry.GetValue(_mode); + break; + case TYPE_STRING: + case TYPE_UCHAR: + default: + SetUserError(ERR_INVALID_PARAMETER); + break; } return _value_entry; } @@ -975,12 +1039,14 @@ class Indicator : public IndicatorBase { /** * Returns the indicator's value. */ + /* virtual double GetValue(int _shift = -1, int _mode = 0) { _shift = _shift >= 0 ? _shift : iparams.GetShift(); istate.is_changed = false; istate.is_ready = false; return EMPTY_VALUE; } + */ }; #endif diff --git a/Indicator.struct.h b/Indicator.struct.h index 851f1d2b4..0ca53f0b9 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -289,29 +289,44 @@ struct IndicatorDataEntry { int GetYear() { return DateTimeStatic::Year(timestamp); } long GetTime() { return timestamp; }; ENUM_DATATYPE GetDataType() { - if (CheckFlags(INDI_ENTRY_FLAG_IS_FLOAT)) { - return TYPE_FLOAT; - } else if (CheckFlags(INDI_ENTRY_FLAG_IS_INT)) { - return TYPE_INT; - } else if (CheckFlags(INDI_ENTRY_FLAG_IS_LONG)) { - return TYPE_LONG; + if (CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) { + return CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED) ? TYPE_DOUBLE : TYPE_FLOAT; + } else { + if (CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { + return CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED) ? TYPE_ULONG : TYPE_LONG; + } else { + return CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED) ? TYPE_UINT : TYPE_INT; + } } - return TYPE_DOUBLE; } - INDICATOR_ENTRY_FLAGS GetDataTypeFlag(ENUM_DATATYPE _dt) { + ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { switch (_dt) { - case TYPE_DOUBLE: - return INDI_ENTRY_FLAG_IS_DOUBLE; - case TYPE_FLOAT: - return INDI_ENTRY_FLAG_IS_FLOAT; + case TYPE_BOOL: + case TYPE_CHAR: + SetUserError(ERR_INVALID_PARAMETER); + break; case TYPE_INT: - return INDI_ENTRY_FLAG_IS_INT; + return INDI_ENTRY_FLAG_NONE; case TYPE_LONG: - return INDI_ENTRY_FLAG_IS_LONG; + return INDI_ENTRY_FLAG_IS_DOUBLED; + case TYPE_UINT: + return INDI_ENTRY_FLAG_IS_UNSIGNED; + case TYPE_ULONG: + return INDI_ENTRY_FLAG_IS_UNSIGNED | INDI_ENTRY_FLAG_IS_DOUBLED; + case TYPE_DOUBLE: + return INDI_ENTRY_FLAG_IS_REAL | INDI_ENTRY_FLAG_IS_DOUBLED; + case TYPE_FLOAT: + return INDI_ENTRY_FLAG_IS_REAL; + case TYPE_STRING: + case TYPE_UCHAR: + SetUserError(ERR_INVALID_PARAMETER); + break; default: + SetUserError(ERR_INVALID_PARAMETER); break; } - return (INDICATOR_ENTRY_FLAGS)0; + SetUserError(ERR_INVALID_PARAMETER); + return INDI_ENTRY_FLAG_NONE; } // Setters. bool Resize(int _size = 0) { return _size > 0 ? ArrayResize(values, _size) > 0 : true; } @@ -448,7 +463,11 @@ struct IndicatorParams { case TYPE_STRING: case TYPE_UCHAR: return (T)param.string_value; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; } + SetUserError(ERR_INVALID_PARAMETER); return (T)WRONG_VALUE; } /* Setters */ diff --git a/Indicator.struct.serialize.h b/Indicator.struct.serialize.h index d7bd36a23..18718e62b 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator.struct.serialize.h @@ -40,32 +40,43 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { // this work? _s.Pass(THIS_REF, (string)i, GetEntry(i), SERIALIZER_FIELD_FLAG_DYNAMIC | // SERIALIZER_FIELD_FLAG_FEATURE); // Can this work? - if (CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLE)) { - _s.Pass(THIS_REF, (string)i, values[i].vdbl, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } else if (CheckFlags(INDI_ENTRY_FLAG_IS_FLOAT)) { - _s.Pass(THIS_REF, (string)i, values[i].vflt, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } else if (CheckFlags(INDI_ENTRY_FLAG_IS_INT)) { - if (!CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { - _s.Pass(THIS_REF, (string)i, values[i].vint, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } else { - // Split for each bit and pass 0 or 1. - for (int j = 0; j < sizeof(int) * 8; ++j) { - int _value = (values[i].vint & (1 << j)) != 0; - _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); + switch (GetDataType()) { + case TYPE_DOUBLE: + _s.Pass(THIS_REF, (string)i, values[i].vdbl, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + break; + case TYPE_FLOAT: + _s.Pass(THIS_REF, (string)i, values[i].vflt, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + break; + case TYPE_INT: + case TYPE_UINT: + if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { + // Split for each bit and pass 0 or 1. + for (int j = 0; j < sizeof(int) * 8; ++j) { + int _value = (values[i].vint & (1 << j)) != 0; + _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); + } + } else { + _s.Pass(THIS_REF, (string)i, values[i].vint, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } - } - } else if (CheckFlags(INDI_ENTRY_FLAG_IS_LONG)) { - if (!CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { - _s.Pass(THIS_REF, (string)i, values[i].vlong, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); - } else { - // Split for each bit and pass 0 or 1. - /* @fixme: j, j already defined. - for (int j = 0; j < sizeof(int) * 8; ++j) { - int _value = (values[i].vlong & (1 << j)) != 0; - _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); + break; + case TYPE_LONG: + case TYPE_ULONG: + if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { + // Split for each bit and pass 0 or 1. + /* @fixme: j, j already defined. + for (int j = 0; j < sizeof(int) * 8; ++j) { + int _value = (values[i].vlong & (1 << j)) != 0; + _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); + } + */ + SetUserError(ERR_INVALID_PARAMETER); + } else { + _s.Pass(THIS_REF, (string)i, values[i].vlong, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } - */ - } + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; } } return SerializerNodeObject; diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 32f2f3eac..6e89b0c53 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -32,8 +32,8 @@ // Structs. struct IndiPatternParams : IndicatorParams { // Struct constructor. - IndiPatternParams(int _shift = 0) : IndicatorParams(INDI_PATTERN, 5, TYPE_INT) { - SetDataValueType(TYPE_INT); + IndiPatternParams(int _shift = 0) : IndicatorParams(INDI_PATTERN, 5, TYPE_UINT) { + SetDataValueType(TYPE_UINT); SetDataValueRange(IDATA_RANGE_BITWISE); shift = _shift; }; @@ -57,7 +57,7 @@ class Indi_Pattern : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual uint GetValue(int _mode = 0, int _shift = 0) { int i; BarOHLC _ohlcs[8]; @@ -123,6 +123,6 @@ class Indi_Pattern : public Indicator { * Returns true if entry is valid (has valid values), otherwise false. */ virtual bool IsValidEntry(IndicatorDataEntry& _entry) { - return !_entry.HasValue(INT_MAX) && _entry.GetMin() >= 0; + return !_entry.HasValue(INT_MAX) && _entry.GetMin() >= 0; } }; diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index ff5b9f621..964a3ab75 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -71,7 +71,7 @@ class Indi_Drawer : public Indicator { IndicatorDataEntry entry(num_args - 1); // @fixit Not sure if we should enforce double. - entry.AddFlags(INDI_ENTRY_FLAG_IS_DOUBLE); + // entry.AddFlags(INDI_ENTRY_FLAG_IS_DOUBLE); if (_action == INDI_ACTION_SET_VALUE) { iparams.SetMaxModes(num_args - 1); diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index 1927a5747..8fd9442f0 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -134,30 +134,6 @@ class Indi_Killzones : public Indicator { */ bool IsValidValue(float _value, unsigned int _mode = 0, int _shift = 0) { return _value > 0.0f; } - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - IndicatorDataEntry _entry = idata.GetByKey(_bar_time); - if (!_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) { - _entry.Resize(iparams.GetMaxModes()); - _entry.timestamp = GetBarTime(_shift); - for (unsigned int _mode = 0; _mode < (uint)iparams.GetMaxModes(); _mode++) { - float _value = GetValue(_mode, _shift); - _entry.values[_mode] = IsValidValue(_value, _mode, _shift) ? _value : 0.0f; - } - _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); - if (_entry.IsValid()) { - _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); - idata.Add(_entry, _bar_time); - } else { - _entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA); - } - } - return _entry; - } - /** * Checks if indicator entry values are valid. */ diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index ffaa52cf3..1db799bdc 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -94,23 +94,4 @@ class Indi_PriceFeeder : public Indicator { } } } - - /** - * Returns the indicator's struct value. - */ - IndicatorDataEntry GetEntry(int _shift = 0) { - long _bar_time = GetBarTime(_shift); - unsigned int _position; - IndicatorDataEntry _entry(iparams.GetMaxModes()); - if (idata.KeyExists(_bar_time, _position)) { - _entry = idata.GetByPos(_position); - } else { - _entry.timestamp = GetBarTime(_shift); - _entry.values[0].Set(GetValue(PRICE_OPEN, _shift)); - _entry.AddFlags(INDI_ENTRY_FLAG_IS_VALID); - _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType())); - idata.Add(_entry, _bar_time); - } - return _entry; - } }; diff --git a/Indicators/indicators.h b/Indicators/indicators.h index 7a7ac1d72..027140284 100644 --- a/Indicators/indicators.h +++ b/Indicators/indicators.h @@ -60,6 +60,7 @@ #include "Indi_Gator.mqh" #include "Indi_HeikenAshi.mqh" #include "Indi_Ichimoku.mqh" +#include "Indi_Killzones.mqh" #include "Indi_MA.mqh" #include "Indi_MACD.mqh" #include "Indi_MFI.mqh" From ad5c9748075e0f9781b706f8e898a5c71cdd925f Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 21:24:54 +0100 Subject: [PATCH 43/97] Task: Adds TaskSetter class --- .github/workflows/test-task.yml | 1 + Task/TaskGetter.h | 2 +- Task/TaskSetter.h | 133 +++++++++++++++++++++++++ Task/TaskSetter.struct.h | 170 ++++++++++++++++++++++++++++++++ Task/TaskSetterBase.h | 58 +++++++++++ Task/tests/TaskSetter.test.mq4 | 28 ++++++ Task/tests/TaskSetter.test.mq5 | 85 ++++++++++++++++ 7 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 Task/TaskSetter.h create mode 100644 Task/TaskSetter.struct.h create mode 100644 Task/TaskSetterBase.h create mode 100644 Task/tests/TaskSetter.test.mq4 create mode 100644 Task/tests/TaskSetter.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index d5869346f..e0b0458c6 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -53,6 +53,7 @@ jobs: - TaskAction.test - TaskCondition.test - TaskGetter.test + - TaskSetter.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index b25ac67f1..ee81da1a9 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -114,7 +114,7 @@ class TaskGetter : protected TaskGetterBase { /* TaskGetterBase methods */ /** - * Runs an action. + * Gets a copy of structure. */ TS Get(const TaskGetterEntry &_entry) { TS _result; diff --git a/Task/TaskSetter.h b/Task/TaskSetter.h new file mode 100644 index 000000000..031da2b3d --- /dev/null +++ b/Task/TaskSetter.h @@ -0,0 +1,133 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides integration with task's actions. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_SETTER_H +#define TASK_SETTER_H + +// Includes. +//#include "TaskSetter.enum.h" +#include "TaskSetter.struct.h" +#include "TaskSetterBase.h" + +/** + * TaskSetter class. + */ +template +class TaskSetter : protected TaskSetterBase { + protected: + // Protected class variables. + TaskSetterEntry entry; // Setter entry. + TO obj; // Object to run the action on. + + public: + /* Special methods */ + + /** + * Default class constructor. + */ + TaskSetter() {} + + /** + * Class constructor with an entry as argument. + */ + TaskSetter(TaskSetterEntry &_entry) : entry(_entry) {} + + /* Main methods */ + + /** + * Runs a current stored action. + */ + bool Set(const TS &_entry_value) { + bool _result = obj.Set(entry, _entry_value); + entry.Set(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); + entry.TriesDec(); + return _result; + } + + /* Setters */ + + /** + * Gets an entry's flag. + */ + bool Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag) const { return entry.Get(_flag); } + + /** + * Gets an entry's property value. + */ + template + T Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop) const { + entry.Get(_prop); + } + + /** + * Gets a reference to the object. + */ + TO *GetObject() { return GetPointer(obj); } + + /* Setters */ + + /** + * Sets an entry's flag. + */ + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value = true) { + entry.Set(_flag, _value); + } + + /** + * Sets an entry's property value. + */ + template + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop, T _value) { + entry.Set(_prop, _value); + } + + /* TaskSetterBase methods */ + + /** + * Sets entry value. + */ + bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + case 0: + _result = Set(_entry_value); + break; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return _result; + } +}; + +#endif // TASK_SETTER_H diff --git a/Task/TaskSetter.struct.h b/Task/TaskSetter.struct.h new file mode 100644 index 000000000..d33715ca3 --- /dev/null +++ b/Task/TaskSetter.struct.h @@ -0,0 +1,170 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Includes TaskSetter's structures. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Includes. +#include "../Data.struct.h" +#include "../Std.h" +#include "Task.enum.h" + +/* Entry for TaskSetter class. */ +struct TaskSetterEntry { + public: + /* Enumerations */ + + // Defines action entry properties. + enum ENUM_TASK_SETTER_ENTRY_PROP { + TASK_SETTER_ENTRY_FLAGS, + TASK_SETTER_ENTRY_FREQUENCY, + TASK_SETTER_ENTRY_ID, + TASK_SETTER_ENTRY_TRIES, + TASK_SETTER_ENTRY_TIME_LAST_GET, + }; + // Defines action entry flags. + enum ENUM_TASK_SETTER_ENTRY_FLAG { + TASK_SETTER_ENTRY_FLAG_NONE = 0 << 0, + TASK_SETTER_ENTRY_FLAG_IS_ACTIVE = 1 << 0, + TASK_SETTER_ENTRY_FLAG_IS_DONE = 1 << 1, + TASK_SETTER_ENTRY_FLAG_IS_FAILED = 1 << 2, + TASK_SETTER_ENTRY_FLAG_IS_INVALID = 1 << 3, + }; + + protected: + unsigned char flags; /* TaskSetter flags. */ + datetime time_last_get; /* Time of the successful get. */ + int freq; /* How often to run (0 for no limit). */ + int id; /* TaskSetter's enum ID. */ + short tries; /* Number of retries left (-1 for unlimited). */ + DataParamEntry args[]; /* TaskSetter arguments. */ + protected: + // Protected methods. + void Init() { SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); } + + public: + // Constructors. + TaskSetterEntry() : flags(0), freq(60), id(WRONG_VALUE), time_last_get(0), tries(-1) { Init(); } + TaskSetterEntry(int _id) + : flags(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_ACTIVE)), + id(_id), + freq(60), + time_last_get(0), + tries(-1) { + Init(); + } + TaskSetterEntry(TaskSetterEntry &_ae) { this = _ae; } + // Flag methods. + bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } + void AddFlags(unsigned char _flags) { flags |= _flags; } + void RemoveFlags(unsigned char _flags) { flags &= ~_flags; } + void SetFlag(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value) { + if (_value) { + AddFlags(_flag); + } else { + RemoveFlags(_flag); + } + } + void SetFlags(unsigned char _flags) { flags = _flags; } + // State methods. + bool HasTriesLeft() const { return tries > 0 || tries == -1; } + bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_ACTIVE)); } + bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_DONE)); } + bool IsFailed() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_FAILED)); } + bool IsInvalid() const { return HasFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID)); } + bool IsValid() const { return !IsInvalid(); } + // Setters. + bool Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag) const { return HasFlag(_flag); } + template + T Get(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop) const { + switch (_prop) { + case TASK_SETTER_ENTRY_FLAGS: + return (T)flags; + case TASK_SETTER_ENTRY_FREQUENCY: + return (T)freq; + case TASK_SETTER_ENTRY_ID: + return (T)id; + case TASK_SETTER_ENTRY_TRIES: + return (T)tries; + case TASK_SETTER_ENTRY_TIME_LAST_RUN: + return (T)time_last_run; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + int GetId() const { return id; } + // Setters. + void TriesDec() { tries -= tries > 0 ? 1 : 0; } + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_FLAG) _flag, bool _value = true) { + SetFlag(_flag, _value); + } + template + void Set(STRUCT_ENUM(TaskSetterEntry, ENUM_TASK_SETTER_ENTRY_PROP) _prop, T _value) { + switch (_prop) { + case TASK_SETTER_ENTRY_FLAGS: // ID (magic number). + flags = (unsigned char)_value; + return; + case TASK_SETTER_ENTRY_FREQUENCY: + freq = (int)_value; + return; + case TASK_SETTER_ENTRY_ID: + id = (int)_value; + SetFlag(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_FLAG_IS_INVALID), id == WRONG_VALUE); + return; + case TASK_SETTER_ENTRY_TRIES: + tries = (short)_value; + return; + case TASK_SETTER_ENTRY_TIME_LAST_GET: + time_last_get = (datetime)_value; + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + void AddArg(MqlParam &_arg) { + // @todo: Add another value to args[]. + } + void SetArgs(ARRAY_REF(MqlParam, _args)) { + // @todo: for(). + } + // Serializers + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "time_last_get", time_last_get); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(this, "args", args); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; +}; diff --git a/Task/TaskSetterBase.h b/Task/TaskSetterBase.h new file mode 100644 index 000000000..88896f915 --- /dev/null +++ b/Task/TaskSetterBase.h @@ -0,0 +1,58 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides a base class for a task's getter. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_SETTER_BASE_H +#define TASK_SETTER_BASE_H + +/** + * TaskSetterBase class. + */ +template +class TaskSetterBase { + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskSetterBase() {} + + /* Main methods */ + + /** + * Sets entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; +}; + +#endif // TASK_SETTER_BASE_H diff --git a/Task/tests/TaskSetter.test.mq4 b/Task/tests/TaskSetter.test.mq4 new file mode 100644 index 000000000..8c3ebc2c1 --- /dev/null +++ b/Task/tests/TaskSetter.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskSetter class. + */ + +// Includes. +#include "TaskSetter.test.mq5" diff --git a/Task/tests/TaskSetter.test.mq5 b/Task/tests/TaskSetter.test.mq5 new file mode 100644 index 000000000..6769309c7 --- /dev/null +++ b/Task/tests/TaskSetter.test.mq5 @@ -0,0 +1,85 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskSetter class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TaskSetter.h" + +enum ENUM_TASK_SETTER_TEST { + TASK_SETTER_TEST01 = 1, + TASK_SETTER_TEST02 = 2, + TASK_SETTER_TEST03 = 3, +}; + +struct TaskSetterTest01Data { + int value; + TaskSetterTest01Data(int _value) : value(_value) {} + int GetValue() const { return value; } + void SetValue(int _value) { value = _value; } +}; + +class TaskSetterTest01 : protected TaskSetterBase { + protected: + TaskSetterTest01Data data; + + public: + TaskSetterTest01() : data(0) {}; + int GetValue() const { return data.GetValue(); } + bool Set(const TaskSetterEntry &_entry, const TaskSetterTest01Data &_entry_value) { + data.SetValue(data.GetValue() + _entry_value.GetValue()); + PrintFormat("Set: %s; value=%d", __FUNCSIG__, data.GetValue()); + return true; + } +}; + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + // Test01 + TaskSetterEntry _entry01(TASK_SETTER_TEST01); + TaskSetterTest01 _test01; + TaskSetterTest01Data _data_entry(1); + _result &= _test01.Set(_entry01, _data_entry); + _data_entry.SetValue(2); + _result &= _test01.Set(_entry01, _data_entry); + _data_entry.SetValue(3); + _result &= _test01.Set(_entry01, _data_entry); + assertTrueOrFail(_result && _test01.GetValue() == 6, "Fail!"); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From aafa1972abe9fed4233d8f76fe53baf5e1a29f26 Mon Sep 17 00:00:00 2001 From: kenorb Date: Wed, 27 Oct 2021 21:48:11 +0100 Subject: [PATCH 44/97] Task: Adds Set() integration to Taskable --- Task/TaskSetter.h | 4 ++-- Task/TaskSetterBase.h | 2 +- Task/Taskable.h | 6 ++++++ Task/tests/Taskable.test.mq5 | 17 ++++++++++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Task/TaskSetter.h b/Task/TaskSetter.h index 031da2b3d..a08f01957 100644 --- a/Task/TaskSetter.h +++ b/Task/TaskSetter.h @@ -67,7 +67,7 @@ class TaskSetter : protected TaskSetterBase { /** * Runs a current stored action. */ - bool Set(const TS &_entry_value) { + bool Set(const TS &_entry_value) { bool _result = obj.Set(entry, _entry_value); entry.Set(STRUCT_ENUM(TaskSetterEntry, TASK_SETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); entry.TriesDec(); @@ -114,7 +114,7 @@ class TaskSetter : protected TaskSetterBase { /* TaskSetterBase methods */ /** - * Sets entry value. + * Sets an entry value. */ bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) { bool _result = false; diff --git a/Task/TaskSetterBase.h b/Task/TaskSetterBase.h index 88896f915..2b6f0ca84 100644 --- a/Task/TaskSetterBase.h +++ b/Task/TaskSetterBase.h @@ -50,7 +50,7 @@ class TaskSetterBase { /* Main methods */ /** - * Sets entry value. + * Sets an entry value. */ virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; }; diff --git a/Task/Taskable.h b/Task/Taskable.h index 88345b0ee..fe610aa77 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -38,6 +38,7 @@ #include "TaskAction.h" #include "TaskCondition.h" #include "TaskGetter.h" +#include "TaskSetter.h" /** * Taskable class. @@ -68,6 +69,11 @@ class Taskable { * Runs an action. */ virtual bool Run(const TaskActionEntry &_entry) = NULL; + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const TS &_entry_value) = NULL; }; #endif // TASKABLE_H diff --git a/Task/tests/Taskable.test.mq5 b/Task/tests/Taskable.test.mq5 index 38160113a..16c01a8de 100644 --- a/Task/tests/Taskable.test.mq5 +++ b/Task/tests/Taskable.test.mq5 @@ -34,6 +34,7 @@ struct TaskableIntValue { int value; // Field to store a double type. public: TaskableIntValue() : value(0) {} + int GetValue() { return value; } void SetValue(int _value) { value = _value; } }; @@ -76,6 +77,16 @@ class TaskTest01 : public Taskable { PrintFormat("%s; sum=%d", __FUNCSIG__, sum); return sum > 0; } + + /** + * Sets an entry value. + */ + bool Set(const TaskSetterEntry &_entry, const TaskableIntValue &_entry_value) { + sum += _entry.GetId(); + data.SetValue(sum); + PrintFormat("%s; sum=%d", __FUNCSIG__, data.GetValue()); + return data.GetValue() > 0; + } }; /** @@ -96,8 +107,12 @@ int OnInit() { TaskGetterEntry _entry_get(2); TaskableIntValue _value = _test01.Get(_entry_get); _result &= _entry_get.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); + // Sets a dummy value. + TaskSetterEntry _entry_set(2); + _result &= _test01.Set(_entry_set, _value); + _result &= _entry_get.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); // Checks the results. - assertTrueOrFail(_result && _test01.GetSum() == 6, "Fail!"); + assertTrueOrFail(_result && _test01.GetSum() == 8, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 00d470c41b4b22168c8120a30e90eb0f4e01849f Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Oct 2021 00:27:18 +0100 Subject: [PATCH 45/97] Task/TaskGetter: Improves logic and test --- Task/TaskGetter.h | 12 +++--------- Task/tests/TaskGetter.test.mq5 | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Task/TaskGetter.h b/Task/TaskGetter.h index ee81da1a9..6d28ee9f8 100644 --- a/Task/TaskGetter.h +++ b/Task/TaskGetter.h @@ -42,12 +42,11 @@ /** * TaskGetter class. */ -template -class TaskGetter : protected TaskGetterBase { +template +class TaskGetter : public TaskGetterBase { protected: // Protected class variables. TaskGetterEntry entry; // Getter entry. - TO obj; // Object to run the action on. public: /* Special methods */ @@ -68,7 +67,7 @@ class TaskGetter : protected TaskGetterBase { * Runs a current stored action. */ TS Get() { - TS _result = obj.Get(entry); + TS _result = Get(entry); entry.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_TIME_LAST_GET), TimeCurrent()); entry.TriesDec(); return _result; @@ -89,11 +88,6 @@ class TaskGetter : protected TaskGetterBase { entry.Get(_prop); } - /** - * Gets a reference to the object. - */ - TO *GetObject() { return GetPointer(obj); } - /* Setters */ /** diff --git a/Task/tests/TaskGetter.test.mq5 b/Task/tests/TaskGetter.test.mq5 index 05760ff6a..8a8761597 100644 --- a/Task/tests/TaskGetter.test.mq5 +++ b/Task/tests/TaskGetter.test.mq5 @@ -41,13 +41,14 @@ struct TaskGetterTest01Data { void SetValue(int _value) { value = _value; } }; -class TaskGetterTest01 : protected TaskGetterBase { +class TaskGetterTest01 : public TaskGetter { protected: TaskGetterTest01Data data; public: TaskGetterTest01(){}; // long GetSum() { return sum; } + TaskGetterTest01Data Get() { return TaskGetter::Get(); } TaskGetterTest01Data Get(const TaskGetterEntry &_entry) { data.SetValue(_entry.GetId()); PrintFormat("Get: %s; value=%d", __FUNCSIG__, data.GetValue()); @@ -62,15 +63,19 @@ int OnInit() { bool _result = true; int _sum = 0; // Test01 + TaskGetterTest01 _test01; TaskGetterEntry _entry01(TASK_GETTER_TEST01); - TaskGetter _getter01(_entry01); - _result &= _getter01.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); - _sum += _getter01.Get().GetValue(); - _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST02); - _sum += _getter01.Get().GetValue(); - _getter01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST03); - _sum += _getter01.Get().GetValue(); - assertTrueOrFail(_result && _sum == 6, "Fail!"); + _result &= _entry01.Get(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_FLAG_IS_ACTIVE)); + _test01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST01); + _sum += _test01.Get().GetValue(); + _sum += _test01.Get(_entry01).GetValue(); + _test01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST02); + _sum += _test01.Get().GetValue(); + _sum += _test01.Get(_entry01).GetValue(); + _test01.Set(STRUCT_ENUM(TaskGetterEntry, TASK_GETTER_ENTRY_ID), TASK_GETTER_TEST03); + _sum += _test01.Get().GetValue(); + _sum += _test01.Get(_entry01).GetValue(); + assertTrueOrFail(_result && _sum == 9, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 6b147aea4f940a055ae95fa644ef3d01b36effca Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Oct 2021 23:15:00 +0100 Subject: [PATCH 46/97] Adds TickManager --- Tick/TickManager.h | 76 +++++++++++++++++++++++++++++++++ Tick/tests/TickManager.test.mq4 | 28 ++++++++++++ Tick/tests/TickManager.test.mq5 | 53 +++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 Tick/TickManager.h create mode 100644 Tick/tests/TickManager.test.mq4 create mode 100644 Tick/tests/TickManager.test.mq5 diff --git a/Tick/TickManager.h b/Tick/TickManager.h new file mode 100644 index 000000000..fc7d00543 --- /dev/null +++ b/Tick/TickManager.h @@ -0,0 +1,76 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Implements TickManager class. + */ + +// Includes. +#include "../BufferStruct.mqh" +#include "TickManager.h" +//#include "TickManager.struct.h" + +/** + * Class to store and manage tick data. + */ +class TickManager : public BufferStruct { + protected: + /* Protected methods */ + + /** + * Init code (called on constructor). + */ + void Init() { + AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); + SetMaxConflicts(86400); + } + + public: + /** + * Default class constructor. + */ + TickManager() { Init(); } + + /** + * Class constructor with parameters. + */ + // TickManager(TickManagerParams &_params) : params(_params) { Init(); } + + /* Getters */ + + /** + * Gets a property value. + */ + // template + // T Get(STRUCT_ENUM(TickManagerParams, ENUM_TSM_PARAMS_PROP) _prop) + // { return params.Get(_prop); } + + /* Setters */ + + /** + * Sets a property value. + */ + // template + // void Set(STRUCT_ENUM(TickManagerParams, ENUM_TSM_PARAMS_PROP) _prop, T _value) + // { params.Set(_prop, _value); } +}; diff --git a/Tick/tests/TickManager.test.mq4 b/Tick/tests/TickManager.test.mq4 new file mode 100644 index 000000000..0956d46bf --- /dev/null +++ b/Tick/tests/TickManager.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TickManager class. + */ + +// Includes. +#include "TickManager.test.mq5" diff --git a/Tick/tests/TickManager.test.mq5 b/Tick/tests/TickManager.test.mq5 new file mode 100644 index 000000000..8bb7b1fa2 --- /dev/null +++ b/Tick/tests/TickManager.test.mq5 @@ -0,0 +1,53 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TickManager class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../TickManager.h" + +TickManager tm; + +/** + * Implements OnInit(). + */ +int OnInit() { + bool _result = true; + // ... + return _result && GetLastError() == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED; +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + MqlTick tick; + ::SymbolInfoTick(_Symbol, tick); + tm.Add(tick, tick.time); + if (tick.time % 3600 == 0) { + PrintFormat("Ticks: %d; Memory %d/%d", tm.Size(), ::TerminalInfoInteger(TERMINAL_MEMORY_USED), + ::TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)); + } +} From 95f05acf0c01a8e9aa6ceda0db33cb0b39d083f2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 29 Oct 2021 14:32:20 +0100 Subject: [PATCH 47/97] Tick/TickManager: Adds TickManagerOverflowListener() --- Tick/TickManager.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Tick/TickManager.h b/Tick/TickManager.h index fc7d00543..befa1d4a9 100644 --- a/Tick/TickManager.h +++ b/Tick/TickManager.h @@ -42,7 +42,7 @@ class TickManager : public BufferStruct { */ void Init() { AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED); - SetMaxConflicts(86400); + SetOverflowListener(TickManagerOverflowListener, 10); } public: @@ -73,4 +73,22 @@ class TickManager : public BufferStruct { // template // void Set(STRUCT_ENUM(TickManagerParams, ENUM_TSM_PARAMS_PROP) _prop, T _value) // { params.Set(_prop, _value); } + + /* Other methods */ + + /** + * Function should return true if resize can be made, or false to overwrite current slot. + */ + static bool TickManagerOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) { + switch (_reason) { + case DICT_OVERFLOW_REASON_FULL: + // We allow resize if dictionary size is less than 86400 slots. + return _size < 86400; + case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS: + default: + // When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused. + break; + } + return false; + } }; From 1e59d35d6daa582ce8a181310b4a9f2a768256f5 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 29 Oct 2021 18:23:07 +0200 Subject: [PATCH 48/97] In the middle of Indicator::GetValue -> GetMixedValue refactoring. --- Indicator.struct.h | 248 +++++++++++++----------- Indicator.struct.serialize.h | 27 +-- IndicatorBase.h | 16 +- Indicators/Bitwise/Indi_Candle.mqh | 2 +- Indicators/Bitwise/Indi_Pattern.mqh | 2 +- Indicators/Indi_AC.mqh | 5 +- Indicators/Indi_AD.mqh | 3 +- Indicators/Indi_ADX.mqh | 2 +- Indicators/Indi_ADXW.mqh | 2 +- Indicators/Indi_AMA.mqh | 2 +- Indicators/Indi_AO.mqh | 2 +- Indicators/Indi_ASI.mqh | 2 +- Indicators/Indi_ATR.mqh | 2 +- Indicators/Indi_Alligator.mqh | 2 +- Indicators/Indi_AppliedPrice.mqh | 2 +- Indicators/Indi_BWMFI.mqh | 2 +- Indicators/Indi_BWZT.mqh | 2 +- Indicators/Indi_Bands.mqh | 2 +- Indicators/Indi_BearsPower.mqh | 2 +- Indicators/Indi_BullsPower.mqh | 2 +- Indicators/Indi_CCI.mqh | 2 +- Indicators/Indi_CHO.mqh | 2 +- Indicators/Indi_CHV.mqh | 2 +- Indicators/Indi_ColorBars.mqh | 2 +- Indicators/Indi_ColorCandlesDaily.mqh | 2 +- Indicators/Indi_ColorLine.mqh | 2 +- Indicators/Indi_CustomMovingAverage.mqh | 2 +- Indicators/Indi_DEMA.mqh | 2 +- Indicators/Indi_DeMarker.mqh | 2 +- Indicators/Indi_Demo.mqh | 2 +- Indicators/Indi_DetrendedPrice.mqh | 2 +- Indicators/Indi_Drawer.mqh | 2 +- Indicators/Indi_Envelopes.mqh | 2 +- Indicators/Indi_Force.mqh | 2 +- Indicators/Indi_FractalAdaptiveMA.mqh | 2 +- Indicators/Indi_Fractals.mqh | 2 +- Indicators/Indi_Gator.mqh | 2 +- Indicators/Indi_HeikenAshi.mqh | 2 +- Indicators/Indi_Ichimoku.mqh | 6 +- Indicators/Indi_MA.mqh | 2 +- Indicators/Indi_MACD.mqh | 2 +- Indicators/Indi_MFI.mqh | 2 +- Indicators/Indi_MassIndex.mqh | 2 +- Indicators/Indi_Momentum.mqh | 2 +- Indicators/Indi_OBV.mqh | 2 +- Indicators/Indi_OsMA.mqh | 2 +- Indicators/Indi_Pivot.mqh | 12 +- Indicators/Indi_PriceChannel.mqh | 2 +- Indicators/Indi_PriceFeeder.mqh | 2 +- Indicators/Indi_PriceVolumeTrend.mqh | 2 +- Indicators/Indi_RS.mqh | 7 +- Indicators/Indi_RSI.mqh | 6 +- Indicators/Indi_RVI.mqh | 2 +- Indicators/Indi_RateOfChange.mqh | 2 +- Indicators/Indi_SAR.mqh | 2 +- Indicators/Indi_StdDev.mqh | 2 +- Indicators/Indi_Stochastic.mqh | 2 +- Indicators/Indi_TEMA.mqh | 2 +- Indicators/Indi_TRIX.mqh | 2 +- Indicators/Indi_UltimateOscillator.mqh | 2 +- Indicators/Indi_VIDYA.mqh | 2 +- Indicators/Indi_VROC.mqh | 2 +- Indicators/Indi_Volumes.mqh | 2 +- Indicators/Indi_WPR.mqh | 2 +- Indicators/Indi_WilliamsAD.mqh | 2 +- Indicators/Indi_ZigZag.mqh | 2 +- Indicators/Indi_ZigZagColor.mqh | 2 +- Indicators/OHLC/Indi_OHLC.mqh | 2 +- Indicators/Price/Indi_Price.mqh | 2 +- Indicators/Special/Indi_Math.mqh | 2 +- tests/IndicatorsTest.mq5 | 10 +- 71 files changed, 250 insertions(+), 212 deletions(-) diff --git a/Indicator.struct.h b/Indicator.struct.h index 0ca53f0b9..e63f82c05 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -45,109 +45,147 @@ struct ChartParams; #include "SerializerNode.enum.h" #include "Storage/ValueStorage.indicator.h" +// Type-less value for IndicatorDataEntryValue structure. +union IndicatorDataEntryTypelessValue { + double vdbl; + float vflt; + int vint; + long vlong; +}; + +// Type-aware value for IndicatorDataEntry class. +struct IndicatorDataEntryValue { + unsigned char flags; + IndicatorDataEntryTypelessValue value; + + // Returns type of the value. + ENUM_DATATYPE GetDataType() { return (ENUM_DATATYPE)((flags & 0xF0) >> 4); } + + // Sets type of the value. + void SetDataType(ENUM_DATATYPE _type) { + // CLearing type. + flags &= 0x0F; + + // Setting type. + flags |= (unsigned char)_type << 4; + } + + // Union operators. + template + T operator*(const T _value) { + return Get() * _value; + } + template + T operator+(const T _value) { + return Get() + _value; + } + template + T operator-(const T _value) { + return Get() - _value; + } + template + T operator/(const T _value) { + return Get() / _value; + } + template + bool operator!=(const T _value) { + return Get() != _value; + } + template + bool operator<(const T _value) { + return Get() < _value; + } + template + bool operator<=(const T _value) { + return Get() <= _value; + } + template + bool operator==(const T _value) { + return Get() == _value; + } + template + bool operator>(const T _value) { + return Get() > _value; + } + template + bool operator>=(const T _value) { + return Get() >= _value; + } + template + void operator=(const T _value) { + Set(_value); + } + // Checkers. + template + bool IsGt(T _value) { + return Get() > _value; + } + template + bool IsLt(T _value) { + return Get() < _value; + } + // Getters. + double GetDbl() { return value.vdbl; } + float GetFloat() { return value.vflt; } + int GetInt() { return value.vint; } + long GetLong() { return value.vlong; } + template + void Get(T &_out) { + _out = Get(); + } + template + T Get() { + T _v; + Get(_v); + return _v; + } + void Get(double &_out) { _out = value.vdbl; } + void Get(float &_out) { _out = value.vflt; } + void Get(int &_out) { _out = value.vint; } + void Get(long &_out) { _out = value.vlong; } + // Setters. + template + void Set(T _value) { + Set(_value); + } + void Set(double _value) { + value.vdbl = _value; + SetDataType(TYPE_DOUBLE); + } + void Set(float _value) { + value.vflt = _value; + SetDataType(TYPE_FLOAT); + } + void Set(int _value) { + value.vint = _value; + SetDataType(TYPE_INT); + } + void Set(unsigned int _value) { + value.vint = (int)_value; + SetDataType(TYPE_UINT); + } + void Set(long _value) { + value.vlong = _value; + SetDataType(TYPE_LONG); + } + void Set(unsigned long _value) { + value.vlong = (long)_value; + SetDataType(TYPE_ULONG); + } + // Serializers. + // SERIALIZER_EMPTY_STUB + SerializerNodeType Serialize(Serializer &_s); + // To string + template + string ToString() { + return (string)Get(); + } +}; + /* Structure for indicator data entry. */ struct IndicatorDataEntry { long timestamp; // Timestamp of the entry's bar. unsigned short flags; // Indicator entry flags. - union IndicatorDataEntryValue { - double vdbl; - float vflt; - int vint; - long vlong; - // Union operators. - template - T operator*(const T _value) { - return Get() * _value; - } - template - T operator+(const T _value) { - return Get() + _value; - } - template - T operator-(const T _value) { - return Get() - _value; - } - template - T operator/(const T _value) { - return Get() / _value; - } - template - bool operator!=(const T _value) { - return Get() != _value; - } - template - bool operator<(const T _value) { - return Get() < _value; - } - template - bool operator<=(const T _value) { - return Get() <= _value; - } - template - bool operator==(const T _value) { - return Get() == _value; - } - template - bool operator>(const T _value) { - return Get() > _value; - } - template - bool operator>=(const T _value) { - return Get() >= _value; - } - template - void operator=(const T _value) { - Set(_value); - } - // Checkers. - template - bool IsGt(T _value) { - return Get() > _value; - } - template - bool IsLt(T _value) { - return Get() < _value; - } - // Getters. - double GetDbl() { return vdbl; } - float GetFloat() { return vflt; } - int GetInt() { return vint; } - long GetLong() { return vlong; } - template - void Get(T &_out) { - _out = Get(); - } - template - T Get() { - T _v; - Get(_v); - return _v; - } - void Get(double &_out) { _out = vdbl; } - void Get(float &_out) { _out = vflt; } - void Get(int &_out) { _out = vint; } - void Get(long &_out) { _out = vlong; } - // Setters. - template - void Set(T _value) { - Set(_value); - } - void Set(double _value) { vdbl = _value; } - void Set(float _value) { vflt = _value; } - void Set(int _value) { vint = _value; } - void Set(unsigned int _value) { vint = (int)_value; } - void Set(long _value) { vlong = _value; } - void Set(unsigned long _value) { vlong = (long)_value; } - // Serializers. - // SERIALIZER_EMPTY_STUB - SerializerNodeType Serialize(Serializer &_s); - // To string - template - string ToString() { - return (string)Get(); - } - }; - ARRAY(IndicatorDataEntryValue, values); // Constructors. @@ -288,17 +326,7 @@ struct IndicatorDataEntry { int GetMonth() { return DateTimeStatic::Month(timestamp); } int GetYear() { return DateTimeStatic::Year(timestamp); } long GetTime() { return timestamp; }; - ENUM_DATATYPE GetDataType() { - if (CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) { - return CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED) ? TYPE_DOUBLE : TYPE_FLOAT; - } else { - if (CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) { - return CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED) ? TYPE_ULONG : TYPE_LONG; - } else { - return CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED) ? TYPE_UINT : TYPE_INT; - } - } - } + ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); } ushort GetDataTypeFlags(ENUM_DATATYPE _dt) { switch (_dt) { case TYPE_BOOL: diff --git a/Indicator.struct.serialize.h b/Indicator.struct.serialize.h index 18718e62b..98e262c60 100644 --- a/Indicator.struct.serialize.h +++ b/Indicator.struct.serialize.h @@ -40,23 +40,26 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { // this work? _s.Pass(THIS_REF, (string)i, GetEntry(i), SERIALIZER_FIELD_FLAG_DYNAMIC | // SERIALIZER_FIELD_FLAG_FEATURE); // Can this work? - switch (GetDataType()) { + switch (values[i].GetDataType()) { case TYPE_DOUBLE: - _s.Pass(THIS_REF, (string)i, values[i].vdbl, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, (string)i, values[i].value.vdbl, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_FLOAT: - _s.Pass(THIS_REF, (string)i, values[i].vflt, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, (string)i, values[i].value.vflt, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); break; case TYPE_INT: case TYPE_UINT: if (CheckFlags(INDI_ENTRY_FLAG_IS_BITWISE)) { // Split for each bit and pass 0 or 1. for (int j = 0; j < sizeof(int) * 8; ++j) { - int _value = (values[i].vint & (1 << j)) != 0; + int _value = (values[i].value.vint & (1 << j)) != 0; _s.Pass(THIS_REF, StringFormat("%d@%d", i, j), _value, SERIALIZER_FIELD_FLAG_FEATURE); } } else { - _s.Pass(THIS_REF, (string)i, values[i].vint, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, (string)i, values[i].value.vint, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; case TYPE_LONG: @@ -71,7 +74,8 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { */ SetUserError(ERR_INVALID_PARAMETER); } else { - _s.Pass(THIS_REF, (string)i, values[i].vlong, SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); + _s.Pass(THIS_REF, (string)i, values[i].value.vlong, + SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE); } break; default: @@ -83,11 +87,12 @@ SerializerNodeType IndicatorDataEntry::Serialize(Serializer &_s) { } /* Method to serialize IndicatorDataEntry's IndicatorDataEntryValue union. */ -SerializerNodeType IndicatorDataEntry::IndicatorDataEntryValue::Serialize(Serializer &_s) { - _s.Pass(THIS_REF, "vdbl", vdbl); - _s.Pass(THIS_REF, "vflt", vflt); - _s.Pass(THIS_REF, "vint", vint); - _s.Pass(THIS_REF, "vlong", vlong); +SerializerNodeType IndicatorDataEntryValue::Serialize(Serializer &_s) { + _s.Pass(THIS_REF, "flags", flags); + _s.Pass(THIS_REF, "vdbl", value.vdbl); + _s.Pass(THIS_REF, "vflt", value.vflt); + _s.Pass(THIS_REF, "vint", value.vint); + _s.Pass(THIS_REF, "vlong", value.vlong); return SerializerNodeObject; }; diff --git a/IndicatorBase.h b/IndicatorBase.h index 42df064ad..7e3477722 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -45,7 +45,6 @@ class Chart; #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" #include "Indicator.struct.signal.h" -#include "Math.h" #include "Object.mqh" #include "Refs.mqh" #include "Serializer.mqh" @@ -835,18 +834,15 @@ class IndicatorBase : public Chart { return value_storages[_mode]; } - /** - * Returns indicator value for a given shift and mode. - */ template - T GetValue(int _shift = 0, int _mode = -1) { - T _result; - int _index = _mode != -1 ? _mode : GetDataSourceMode(); - GetEntry(_shift).values[_index].Get(_result); - ResetLastError(); - return _result; + T GetValue(int _shift = 0, int _mode = 0) { + T _out; + GetMixedValue(_shift, _mode).Get(_out); + return _out; } + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) = NULL; + /** * Returns price corresponding to indicator value for a given shift and mode. * diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index 4c5f9f086..8880970c3 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -66,7 +66,7 @@ class Indi_Candle : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; BarOHLC _ohlcs[1]; diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 6e89b0c53..8a1327df2 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -57,7 +57,7 @@ class Indi_Pattern : public Indicator { /** * Returns the indicator's value. */ - virtual uint GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { int i; BarOHLC _ohlcs[8]; diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 2ce43dad3..8e6a2ca23 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -33,6 +33,7 @@ double iAC(string _symbol, int _tf, int _shift) { return Indi_AC::iAC(_symbol, ( struct IndiACParams : IndicatorParams { // Struct constructor. IndiACParams(int _shift = 0) : IndicatorParams(INDI_AC, 1, TYPE_DOUBLE) { + SetDataSourceType(IDATA_ICUSTOM); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Accelerator"); shift = _shift; @@ -97,8 +98,8 @@ class Indi_AC : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { - double _value = EMPTY_VALUE; + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + IndicatorDataEntryValue _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index a4422f983..1e3e853c2 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -34,6 +34,7 @@ struct IndiADParams : IndicatorParams { IndiADParams(int _shift = 0) : IndicatorParams(INDI_AD, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\AD"); + SetDataSourceType(IDATA_ICUSTOM); shift = _shift; }; IndiADParams(IndiADParams &_params, ENUM_TIMEFRAMES _tf) { @@ -96,7 +97,7 @@ class Indi_AD : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index 41ba460dc..bc20fd824 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -114,7 +114,7 @@ class Indi_ADX : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 373cdf742..52873bf82 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -215,7 +215,7 @@ class Indi_ADXW : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index dcd840b1b..d5d5e3137 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -199,7 +199,7 @@ class Indi_AMA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 1dbe5927c..fb29de8af 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -100,7 +100,7 @@ class Indi_AO : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index efc813c42..f018085b4 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -155,7 +155,7 @@ class Indi_ASI : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_ICUSTOM: diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index f3bfa57b1..0ccc99855 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -102,7 +102,7 @@ class Indi_ATR : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index a44faa5ab..a8b8ea71c 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -161,7 +161,7 @@ class Indi_Alligator : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode, int _shift = 0) { #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index 30514d924..f7bb5911c 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -72,7 +72,7 @@ class Indi_AppliedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_INDICATOR: diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index b0d91124f..58057f52e 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -111,7 +111,7 @@ class Indi_BWMFI : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = BWMFI_BUFFER, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = BWMFI_BUFFER, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index 9f5f0bd53..d2b932378 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -172,7 +172,7 @@ class Indi_BWZT : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index ad80f2472..07623c77d 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -237,7 +237,7 @@ class Indi_Bands : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual double GetValue(int _mode = BAND_BASE, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = BAND_BASE, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index 420deaad7..c57530b90 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -103,7 +103,7 @@ class Indi_BearsPower : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index ffe777e95..7af5ea215 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -103,7 +103,7 @@ class Indi_BullsPower : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index ea9f16318..6887afb80 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -145,7 +145,7 @@ class Indi_CCI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index f89b05081..f86691934 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -166,7 +166,7 @@ class Indi_CHO : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index 616a9570d..f7cba3d14 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -162,7 +162,7 @@ class Indi_CHV : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index b319494e3..4f63a21b6 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -113,7 +113,7 @@ class Indi_ColorBars : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index bf46d7cba..1872d25ce 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -109,7 +109,7 @@ class Indi_ColorCandlesDaily : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index bde254e25..87a65b243 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -172,7 +172,7 @@ class Indi_ColorLine : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 2cd2556b6..5309fd554 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -66,7 +66,7 @@ class Indi_CustomMovingAverage : public Indicator /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_ICUSTOM: diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 9d1c7d6af..1400ffd6c 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -166,7 +166,7 @@ class Indi_DEMA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index f6cfdbc49..f173a8217 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -101,7 +101,7 @@ class Indi_DeMarker : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 4edc68cd1..d9f66f828 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -72,7 +72,7 @@ class Indi_Demo : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _shift, THIS_PTR); if (iparams.is_draw) { draw.DrawLineTo(GetName(), GetBarTime(_shift), _value); diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index 6c07a1996..898cdb791 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -115,7 +115,7 @@ class Indi_DetrendedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 964a3ab75..e65d11fea 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -170,7 +170,7 @@ class Indi_Drawer : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index b67367e5d..04b26d892 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -195,7 +195,7 @@ class Indi_Envelopes : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index df130437c..e59968786 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -116,7 +116,7 @@ class Indi_Force : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 74523b2b5..284866b17 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -134,7 +134,7 @@ class Indi_FrAMA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index 6a7c7c263..e23b23c37 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -101,7 +101,7 @@ class Indi_Fractals : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 8c1147d9d..60cb4f812 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -168,7 +168,7 @@ class Indi_Gator : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 79bea8f4e..fa5277a17 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -195,7 +195,7 @@ class Indi_HeikenAshi : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = HA_OPEN, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = HA_OPEN, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 7f7b0e1e7..43a3daa48 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -141,7 +141,7 @@ class Indi_Ichimoku : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: @@ -167,9 +167,9 @@ class Indi_Ichimoku : public Indicator { #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), // so we are duplicating it. - _entry.values[0] = GetValue(LINE_TENKANSEN, _shift); + _entry.values[0] = GetMixedValue(LINE_TENKANSEN, _shift); #endif - _entry.values[LINE_CHIKOUSPAN] = GetValue(LINE_CHIKOUSPAN, _shift + 26); + _entry.values[LINE_CHIKOUSPAN] = GetMixedValue(LINE_CHIKOUSPAN, _shift + 26); } /** diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 770d77a12..133d7e306 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -625,7 +625,7 @@ class Indi_MA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index 273a0cb82..1af133239 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -113,7 +113,7 @@ class Indi_MACD : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 2853da83f..93b437faa 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -110,7 +110,7 @@ class Indi_MFI : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 534d66154..e27105e14 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -153,7 +153,7 @@ class Indi_MassIndex : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 7118eadcd..9778530f3 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -140,7 +140,7 @@ class Indi_Momentum : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 485988a3d..d5bfe8b71 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -117,7 +117,7 @@ class Indi_OBV : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index f269a8a90..0bb1302e2 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -110,7 +110,7 @@ class Indi_OsMA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index daa69e196..dc3711dbd 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -70,9 +70,13 @@ class Indi_Pivot : public Indicator { _entry.timestamp = GetBarTime(_ishift); if (_ohlc.IsValid()) { _entry.Resize(iparams.GetMaxModes()); - _ohlc.GetPivots(GetMethod(), _entry.values[0].vflt, _entry.values[1].vflt, _entry.values[2].vflt, - _entry.values[3].vflt, _entry.values[4].vflt, _entry.values[5].vflt, _entry.values[6].vflt, - _entry.values[7].vflt, _entry.values[8].vflt); + _ohlc.GetPivots(GetMethod(), _entry.values[0].value.vflt, _entry.values[1].value.vflt, + _entry.values[2].value.vflt, _entry.values[3].value.vflt, _entry.values[4].value.vflt, + _entry.values[5].value.vflt, _entry.values[6].value.vflt, _entry.values[7].value.vflt, + _entry.values[8].value.vflt); + for (int i = 0; i <= 8; ++i) { + _entry.values[i].SetDataType(TYPE_FLOAT); + } } GetEntryAlter(_entry, _ishift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); @@ -94,7 +98,7 @@ class Indi_Pivot : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { return GetEntry(_shift)[_mode]; } + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { return GetEntry(_shift)[_mode]; } /** * Checks if indicator entry values are valid. diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index e35c4be06..bb60bfaa8 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -105,7 +105,7 @@ class Indi_PriceChannel : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; switch (iparams.idstype) { diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index 1db799bdc..24e35c8b1 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -75,7 +75,7 @@ class Indi_PriceFeeder : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(ENUM_APPLIED_PRICE _ap, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { int data_size = ArraySize(iparams.price_data); if (_shift >= data_size || _shift < 0) return DBL_MIN; diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index 47502b7dc..eca779fe3 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -120,7 +120,7 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index d78e54aea..50746a0b1 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -78,17 +78,16 @@ class Indi_RS : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { - double _value = EMPTY_VALUE; + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { switch (iparams.idstype) { case IDATA_MATH: - _value = imath[_mode].Ptr().GetValue(); + return imath[_mode].Ptr().GetMixedValue(); break; default: SetUserError(ERR_INVALID_PARAMETER); break; } - return _value; + return EMPTY_VALUE; } /** diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 50fa4662c..f6441d8fd 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -52,6 +52,7 @@ struct IndiRSIParams : IndicatorParams { : applied_price(_ap), IndicatorParams(INDI_RSI, 1, TYPE_DOUBLE) { shift = _shift; SetDataValueRange(IDATA_RANGE_RANGE); + // SetDataSourceType(IDATA_ICUSTOM); SetCustomIndicatorName("Examples\\RSI"); SetPeriod(_period); }; @@ -286,8 +287,10 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; + int _bars_calc; + double _res[]; switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; @@ -297,6 +300,7 @@ class Indi_RSI : public Indicator { istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ iparams.GetPeriod(), iparams.GetAppliedPrice() /* ] */, 0, _shift); + Print(_value); break; case IDATA_INDICATOR: _value = Indi_RSI::iRSIOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), iparams.GetPeriod(), diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index e99f76a80..535668610 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -102,7 +102,7 @@ class Indi_RVI : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 9abef6869..f8eddcbf2 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -109,7 +109,7 @@ class Indi_RateOfChange : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index c86f2c47d..3a9c59f26 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -101,7 +101,7 @@ class Indi_SAR : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 3d468e2cc..1d582e028 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -224,7 +224,7 @@ class Indi_StdDev : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index b472f0510..8fbbaafba 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -118,7 +118,7 @@ class Indi_Stochastic : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index b47e46a3f..005d6dc98 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -126,7 +126,7 @@ class Indi_TEMA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index 5b83bc38d..8b5518c98 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -127,7 +127,7 @@ class Indi_TRIX : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 634e5cbee..4b3dedc19 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -208,7 +208,7 @@ class Indi_UltimateOscillator : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 34742ae39..f2410a0b9 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -147,7 +147,7 @@ class Indi_VIDYA : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 159e43a28..65349c501 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -130,7 +130,7 @@ class Indi_VROC : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 104f0890a..8b3e6bb98 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -124,7 +124,7 @@ class Indi_Volumes : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 1327c4e5b..6d20ecc27 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -100,7 +100,7 @@ class Indi_WPR : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 982bd6beb..5c883fbdc 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -124,7 +124,7 @@ class Indi_WilliamsAD : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index d36bd4267..0e9c059bc 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -334,7 +334,7 @@ class Indi_ZigZag : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 91a26b49d..def4e54eb 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -268,7 +268,7 @@ class Indi_ZigZagColor : public Indicator { /** * Returns the indicator's value. */ - double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { ResetLastError(); double _value = EMPTY_VALUE; switch (iparams.idstype) { diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index 2765da935..8fcef14bf 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -60,7 +60,7 @@ class Indi_OHLC : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { ENUM_APPLIED_PRICE _ap = PRICE_OPEN; switch (_mode) { case INDI_OHLC_CLOSE: diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 804c64664..622edf907 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -62,7 +62,7 @@ class Indi_Price : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { return ChartStatic::iPrice(iparams.GetAppliedPrice(), GetSymbol(), GetTf(), _shift); } diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index 66fa5e021..175bde0bc 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -93,7 +93,7 @@ class Indi_Math : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_INDICATOR: diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index e66d8abef..72fb277be 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -70,7 +70,7 @@ int OnInit() { assertEqualOrFail(_LastError, ERR_NO_ERROR, StringFormat("Error: %d", GetLastError())); ResetLastError(); // Print indicator values. - _result &= PrintIndicators(__FUNCTION__); + //_result &= PrintIndicators(__FUNCTION__); assertEqualOrFail(_LastError, ERR_NO_ERROR, StringFormat("Error: %d", GetLastError())); ResetLastError(); bar_processed = 0; @@ -107,8 +107,8 @@ void OnTick() { IndicatorDataEntry _entry(_indi.GetEntry()); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY)) && _entry.IsValid()) { PrintFormat("%s: bar %d: %s", _indi.GetFullName(), bar_processed, _indi.ToString()); - tested.Set(iter.Key(), true); // Mark as tested. - indis.Unset(iter.Key()); + // tested.Set(iter.Key(), true); // Mark as tested. + // indis.Unset(iter.Key()); } } } @@ -250,7 +250,7 @@ bool InitIndicators() { // Relative Strength Index (RSI). IndiRSIParams rsi_params(14, PRICE_OPEN); - indis.Push(new Indi_RSI(rsi_params)); + indis.Push(_indi_test = new Indi_RSI(rsi_params)); // Relative Strength Index (RSI). IndiRSIParams rsi_over_blt_stddev_params(); @@ -516,7 +516,7 @@ bool InitIndicators() { // Pattern Detector. IndiPatternParams pattern_params(); - indis.Push(_indi_test = new Indi_Pattern(pattern_params)); + indis.Push(new Indi_Pattern(pattern_params)); // Pivot. IndiPivotParams pivot_params(); From 111375d5604ac647c02e074b14ce20d076639d60 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 29 Oct 2021 22:25:55 +0100 Subject: [PATCH 49/97] Chart3D: Disables broken code, formats code --- 3D/Chart3D.h | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 86175fd55..9167e2b16 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -26,11 +26,11 @@ */ #include "../Bar.struct.h" +#include "../Indicators/Indi_MA.mqh" +#include "../Instances.h" #include "../Refs.mqh" #include "../SerializerConverter.mqh" #include "../SerializerJson.mqh" -#include "../Indicators/Indi_MA.mqh" -#include "../Instances.h" #include "Chart3DCandles.h" #include "Chart3DType.h" #include "Cube.h" @@ -111,9 +111,7 @@ class Chart3D : public Dynamic { Shader* GetShaderPS() { return shader_ps.Ptr(); } - Chart3DType* GetCurrentRenderer() { - return current_renderer; - } + Chart3DType* GetCurrentRenderer() { return current_renderer; } Chart3DType* GetRenderer(Device* _device) { if (!initialized) { @@ -148,7 +146,11 @@ class Chart3D : public Dynamic { /** * Returns given bar's OHLC. */ - BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { return price_fetcher(_tf, _shift); } + BarOHLC GetPrice(ENUM_TIMEFRAMES _tf, int _shift) { + BarOHLC _ohlc; + return _ohlc; + // return price_fetcher(_tf, _shift); // @fixme: 'price_fetcher' - internal error #%d + } /** * Return first shift that are visible on the screen. Values is away from 0. @@ -164,14 +166,20 @@ class Chart3D : public Dynamic { * Returns lowest price of bars on the screen. */ float GetMinBarsPrice() { - return (float)ChartStatic::iLow(Symbol(), PERIOD_CURRENT, ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + return (float)ChartStatic::iLow( + Symbol(), PERIOD_CURRENT, + ChartStatic::iLowest(Symbol(), PERIOD_CURRENT, MODE_LOW, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), + GetBarsVisibleShiftEnd())); } /** * Returns highest price of bars on the screen. */ float GetMaxBarsPrice() { - return (float)ChartStatic::iHigh(Symbol(), PERIOD_CURRENT, ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); + return (float)ChartStatic::iHigh( + Symbol(), PERIOD_CURRENT, + ChartStatic::iHighest(Symbol(), PERIOD_CURRENT, MODE_HIGH, + GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd(), GetBarsVisibleShiftEnd())); } /** @@ -201,7 +209,8 @@ class Chart3D : public Dynamic { void Render(Device* _device) { Chart3DType* _type_renderer = GetRenderer(_device); - BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); + BarOHLC _ohlc; + // BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); // @fixme: 'price_fetcher' - internal error #%d #ifdef __debug__ Print(SerializerConverter::FromObject(_ohlc).ToString()); From 6e05989defaf3bd42a72f4839bc6ba13452234d3 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 29 Oct 2021 22:26:57 +0100 Subject: [PATCH 50/97] CompileTest: Adds 3D includes --- tests/CompileTest.mq5 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index f9baa3e85..ddcdabd5b 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -25,6 +25,13 @@ */ // Includes. +#include "../3D/Chart3D.h" +#include "../3D/Cube.h" +#include "../3D/Devices/MTDX/MTDXDevice.h" +#include "../3D/Devices/MTDX/MTDXIndexBuffer.h" +#include "../3D/Devices/MTDX/MTDXShader.h" +#include "../3D/Devices/MTDX/MTDXVertexBuffer.h" +#include "../3D/Frontends/MT5Frontend.h" #include "../Account.mqh" #include "../Action.mqh" #include "../Array.mqh" From d9a0b3a4436cbd3187fb3d446b44a3c42d4402e2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 29 Oct 2021 23:29:34 +0100 Subject: [PATCH 51/97] 3D: Fixes compilation under MQL4 --- 3D/Chart3D.h | 6 +++++- 3D/Cube.h | 6 +++++- 3D/Devices/MTDX/MTDXShader.h | 2 ++ 3D/Interface.h | 12 +++++++++++- 3D/Math.h | 8 ++++++++ tests/CompileTest.mq5 | 6 +++++- 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/3D/Chart3D.h b/3D/Chart3D.h index 9167e2b16..aedfdbe05 100644 --- a/3D/Chart3D.h +++ b/3D/Chart3D.h @@ -37,9 +37,11 @@ #include "Device.h" #include "Interface.h" -// Resources. +#ifdef __MQL5__ +// Resource variables. #resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; #resource "Shaders/chart3d_ps.hlsl" as string Chart3DShaderSourcePS; +#endif typedef BarOHLC (*Chart3DPriceFetcher)(ENUM_TIMEFRAMES, int); @@ -94,7 +96,9 @@ class Chart3D : public Dynamic { offset.x = offset.y = 0.0f; offset.z = 25.0f; initialized = false; +#ifdef __MQL5__ Interface::AddListener(chart3d_interface_listener, &this); +#endif } void OnInterfaceEvent(InterfaceEvent& _event) { diff --git a/3D/Cube.h b/3D/Cube.h index b4070b7f3..0bc9038ff 100644 --- a/3D/Cube.h +++ b/3D/Cube.h @@ -28,9 +28,11 @@ #include "Face.h" #include "Mesh.h" -// Resources. +#ifdef __MQL5__ +// Resource variables. #resource "Shaders/cube_ps.hlsl" as string ShaderCubeSourcePS; #resource "Shaders/cube_vs.hlsl" as string ShaderCubeSourceVS; +#endif /** * Cube mesh. @@ -70,6 +72,7 @@ class Cube : public Mesh { AddFace(f6); } +#ifdef __MQL5__ /** * Initializes graphics device-related things. */ @@ -77,4 +80,5 @@ class Cube : public Mesh { SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout)); SetShaderPS(_device.PixelShader(ShaderCubeSourcePS)); } +#endif }; diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h index dbde130ad..c3dad254a 100644 --- a/3D/Devices/MTDX/MTDXShader.h +++ b/3D/Devices/MTDX/MTDXShader.h @@ -117,6 +117,7 @@ class MTDXShader : public Shader { ResetLastError(); } +#ifdef __MQL5__ /** * Converts vertex layout's item into required DX's color format. */ @@ -139,6 +140,7 @@ class MTDXShader : public Shader { Alert("Wrong vertex layout!"); return (ENUM_DX_FORMAT)0; } +#endif /** * Sets custom input buffer for shader. diff --git a/3D/Interface.h b/3D/Interface.h index 6ea02fba6..d4e1c74bc 100644 --- a/3D/Interface.h +++ b/3D/Interface.h @@ -47,7 +47,12 @@ struct InterfaceEvent { } data; }; - +#ifdef __MQL5__ +/** + * "OnChart" event handler function (MQL5 only). + * + * Invoked when the ChartEvent event occurs. + */ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { datetime _dt; double _mp; @@ -65,6 +70,7 @@ void OnChartEvent(const int id, const long& lparam, const double& dparam, const Interface::FireEvent(_event); } } +#endif typedef void (*InterfaceListener)(InterfaceEvent&, void*); @@ -85,6 +91,7 @@ class Interface static int mouse_pos_y; static bool initialized; +#ifdef __MQL5__ static void AddListener(InterfaceListener _listener, void* _target) { if (!initialized) { ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); @@ -120,10 +127,13 @@ class Interface static int GetMouseY() { return mouse_pos_y; } +#endif }; +#ifdef __MQL5__ Interface::Installation Interface::installations[]; bool Interface::mouse_was_down = false; int Interface::mouse_pos_x = 0; int Interface::mouse_pos_y = 0; bool Interface::initialized = false; +#endif diff --git a/3D/Math.h b/3D/Math.h index ae74f4092..5a496e0e9 100644 --- a/3D/Math.h +++ b/3D/Math.h @@ -3143,6 +3143,7 @@ void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &i return; } +#ifdef __MQL5__ if ((float)fabs(_matrix.m[2][2]) != 1.0f) { sinb = (float)sqrt(1.0f - _matrix.m[2][2] * _matrix.m[2][2]); alpha = (float)atan2(_matrix.m[2][1] / sinb, _matrix.m[2][0] / sinb); @@ -3153,6 +3154,13 @@ void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &i beta = 0.0f; gamma = 0.0f; } +#else + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + sinb = 0.0f; +#endif + //--- DXSHRotateZ(temp, order, gamma, in); rotate_X(temp1, order, 1.0f, temp); diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index ddcdabd5b..dea9802e4 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -24,7 +24,8 @@ * Test compilation of all class files. */ -// Includes. +// 3D includes (MQL5 only). +#ifdef __MQL5__ #include "../3D/Chart3D.h" #include "../3D/Cube.h" #include "../3D/Devices/MTDX/MTDXDevice.h" @@ -32,6 +33,9 @@ #include "../3D/Devices/MTDX/MTDXShader.h" #include "../3D/Devices/MTDX/MTDXVertexBuffer.h" #include "../3D/Frontends/MT5Frontend.h" +#endif + +// Includes. #include "../Account.mqh" #include "../Action.mqh" #include "../Array.mqh" From 71c58c0ff7ffd1c872d21c6154015709472304c1 Mon Sep 17 00:00:00 2001 From: kenorb Date: Fri, 29 Oct 2021 23:29:57 +0100 Subject: [PATCH 52/97] 3D: Code reformats --- 3D/Chart3DCandles.h | 5 +++-- 3D/Chart3DType.h | 4 +--- 3D/Device.h | 10 +++------- 3D/Frontend.h | 6 ++---- 3D/Frontends/MT5Frontend.h | 8 ++++---- 3D/Interface.h | 16 ++++------------ 3D/Math.h | 8 ++++---- 7 files changed, 21 insertions(+), 36 deletions(-) diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h index 8598dec5b..1340d9be5 100644 --- a/3D/Chart3DCandles.h +++ b/3D/Chart3DCandles.h @@ -66,7 +66,7 @@ class Chart3DCandles : public Chart3DType { cube1.Ptr().GetTSR().translation.y = chart3d.GetPriceScale(_ohlc.GetMinOC()) + _height / 2; cube1.Ptr().GetTSR().scale.y = _height; - //Print(cube1.Ptr().GetTSR().translation.y); + // Print(cube1.Ptr().GetTSR().translation.y); cube1.Ptr().GetMaterial().SetColor(higher ? 0x22FF11 : 0xFF1122); _device.Render(cube1.Ptr()); @@ -93,7 +93,8 @@ class Chart3DCandles : public Chart3DType { cube3.Ptr().GetTSR().translation.y = _y; cube3.Ptr().GetTSR().scale.x = 200.0f; - _device.DrawText(5, _y, StringFormat("%." + IntegerToString(_digits) + "f", _s), 0x90FFFFFF, TA_LEFT | TA_VCENTER, GFX_DRAW_TEXT_FLAG_2D_COORD_X); + _device.DrawText(5, _y, StringFormat("%." + IntegerToString(_digits) + "f", _s), 0x90FFFFFF, TA_LEFT | TA_VCENTER, + GFX_DRAW_TEXT_FLAG_2D_COORD_X); cube3.Ptr().GetMaterial().SetColor(0x333333); _device.Render(cube3.Ptr()); diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h index 66e458212..9e49737f7 100644 --- a/3D/Chart3DType.h +++ b/3D/Chart3DType.h @@ -45,9 +45,7 @@ class Chart3DType : public Dynamic { */ Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {} - Device* GetDevice() { - return device; - } + Device* GetDevice() { return device; } /** * Renders chart. diff --git a/3D/Device.h b/3D/Device.h index eb54420a2..d7b64f94f 100644 --- a/3D/Device.h +++ b/3D/Device.h @@ -35,11 +35,7 @@ #include "Shader.h" #include "VertexBuffer.h" -enum GFX_DRAW_TEXT_FLAGS { - GFX_DRAW_TEXT_FLAG_NONE, - GFX_DRAW_TEXT_FLAG_2D_COORD_X, - GFX_DRAW_TEXT_FLAG_2D_COORD_Y -}; +enum GFX_DRAW_TEXT_FLAGS { GFX_DRAW_TEXT_FLAG_NONE, GFX_DRAW_TEXT_FLAG_2D_COORD_X, GFX_DRAW_TEXT_FLAG_2D_COORD_Y }; enum ENUM_CLEAR_BUFFER_TYPE { CLEAR_BUFFER_TYPE_COLOR, CLEAR_BUFFER_TYPE_DEPTH }; @@ -201,7 +197,6 @@ class Device : public Dynamic { IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); - SetMaterial(_mesh.GetMaterial()); PushTransform(_mesh.GetTSR()); @@ -264,7 +259,8 @@ class Device : public Dynamic { /** * Enqueues text to be drawn directly into the pixel buffer. Queue will be processed in the Device::End() method. */ - void DrawText(float _x, float _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0, unsigned int _flags = 0) { + void DrawText(float _x, float _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0, + unsigned int _flags = 0) { DViewport _viewport; _viewport.x = 0; _viewport.y = 0; diff --git a/3D/Frontend.h b/3D/Frontend.h index 1870fb9bd..8080c65d4 100644 --- a/3D/Frontend.h +++ b/3D/Frontend.h @@ -40,8 +40,7 @@ struct DrawTextQueueItem { */ class Frontend : public Dynamic { protected: - - DrawTextQueueItem draw_text_queue[]; + DrawTextQueueItem draw_text_queue[]; public: /** @@ -105,8 +104,7 @@ class Frontend : public Dynamic { ArrayResize(draw_text_queue, 0); } -protected: - + protected: /** * Draws text directly into the pixel buffer. Should be executed after all 3d drawing. */ diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h index 723e2c2be..9bcec9e73 100644 --- a/3D/Frontends/MT5Frontend.h +++ b/3D/Frontends/MT5Frontend.h @@ -161,13 +161,13 @@ class MT5Frontend : public Frontend { */ virtual void DrawTextNow(int _x, int _y, string _text, unsigned int _color = 0xFFFFFFFF, unsigned int _align = 0) { TextSetFont("Arial", -80, FW_EXTRABOLD, 0); - #ifdef __debug__ +#ifdef __debug__ Print("TextSetFont: LastError = ", GetLastError()); - #endif +#endif TextOut(_text, _x, _y, _align, image, Width(), Height(), _color, COLOR_FORMAT_ARGB_NORMALIZE); - #ifdef __debug__ +#ifdef __debug__ Print("TextOut: LastError = ", GetLastError()); - #endif +#endif } }; diff --git a/3D/Interface.h b/3D/Interface.h index d4e1c74bc..87015f3a4 100644 --- a/3D/Interface.h +++ b/3D/Interface.h @@ -59,7 +59,6 @@ void OnChartEvent(const int id, const long& lparam, const double& dparam, const int _window = 0; InterfaceEvent _event; - if (id == CHART_EVENT_MOUSE_MOVE) { Interface::mouse_pos_x = (int)lparam; Interface::mouse_pos_y = (int)dparam; @@ -74,12 +73,9 @@ void OnChartEvent(const int id, const long& lparam, const double& dparam, const typedef void (*InterfaceListener)(InterfaceEvent&, void*); -class Interface -{ +class Interface { public: - - struct Installation - { + struct Installation { InterfaceListener listener; void* target; }; @@ -120,13 +116,9 @@ class Interface } } - static int GetMouseX() { - return mouse_pos_x; - } + static int GetMouseX() { return mouse_pos_x; } - static int GetMouseY() { - return mouse_pos_y; - } + static int GetMouseY() { return mouse_pos_y; } #endif }; diff --git a/3D/Math.h b/3D/Math.h index 5a496e0e9..e631a214a 100644 --- a/3D/Math.h +++ b/3D/Math.h @@ -3155,10 +3155,10 @@ void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &i gamma = 0.0f; } #else - alpha = 0.0f; - beta = 0.0f; - gamma = 0.0f; - sinb = 0.0f; + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + sinb = 0.0f; #endif //--- From f5a0482b0479cde95a2284a58b74e686ed839745 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 31 Oct 2021 18:34:18 +0000 Subject: [PATCH 53/97] Indicators: Adds Indi_TickMt --- .github/workflows/test-indicators-tick.yml | 65 ++++++++++++++++++ Indicator.enum.h | 5 +- Indicators/Tick/Indi_TickMt.mqh | 76 ++++++++++++++++++++++ Indicators/Tick/tests/Indi_TickMt.test.mq4 | 27 ++++++++ Indicators/Tick/tests/Indi_TickMt.test.mq5 | 60 +++++++++++++++++ 5 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test-indicators-tick.yml create mode 100644 Indicators/Tick/Indi_TickMt.mqh create mode 100644 Indicators/Tick/tests/Indi_TickMt.test.mq4 create mode 100644 Indicators/Tick/tests/Indi_TickMt.test.mq5 diff --git a/.github/workflows/test-indicators-tick.yml b/.github/workflows/test-indicators-tick.yml new file mode 100644 index 000000000..25eabe43c --- /dev/null +++ b/.github/workflows/test-indicators-tick.yml @@ -0,0 +1,65 @@ +--- +name: Test Indicators (Tick) + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Indicator**' + - 'Indicators/Tick/**' + - '.github/workflows/test-indicators-tick.yml' + push: + paths: + - 'Indicator**' + - 'Indicators/Tick/**' + - '.github/workflows/test-indicators-tick.yml' + +jobs: + + Compile: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + uses: fx31337/mql-compile-action@master + with: + init-platform: true + path: 'Indicators/Tick/tests' + verbose: true + - name: Print compiled files + run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' + shell: powershell + - name: Upload artifacts (MQL4) + uses: actions/upload-artifact@v2 + with: + name: files-ex4 + path: '**/*.ex4' + - name: Upload artifacts (MQL5) + uses: actions/upload-artifact@v2 + with: + name: files-ex5 + path: '**/*.ex5' + + Indicators-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Indicators/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Indi_Tick.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + BtDays: 4-8 + BtMonths: 1 + BtYears: 2020 + TestExpert: ${{ matrix.test }} + timeout-minutes: 10 diff --git a/Indicator.enum.h b/Indicator.enum.h index 1587ce083..192182a2d 100644 --- a/Indicator.enum.h +++ b/Indicator.enum.h @@ -96,7 +96,7 @@ enum ENUM_INDICATOR_TYPE { INDI_OSMA, // OsMA INDI_PATTERN, // Pattern Detector INDI_PIVOT, // Pivot Detector - INDI_PRICE, // Price Indicator + INDI_PRICE, // Price INDI_PRICE_CHANNEL, // Price Channel INDI_PRICE_FEEDER, // Indicator which returns prices from custom array INDI_PRICE_VOLUME_TREND, // Price and Volume Trend @@ -114,7 +114,8 @@ enum ENUM_INDICATOR_TYPE { INDI_STOCHASTIC, // Stochastic Oscillator INDI_SVE_BB, // SVE Bollinger Bands INDI_TEMA, // Triple Exponential Moving Average - INDI_TMA_TRUE, /// Triangular Moving Average True + INDI_TICK, // Tick + INDI_TMA_TRUE, // Triangular Moving Average True INDI_TRIX, // Triple Exponential Moving Averages Oscillator INDI_ULTIMATE_OSCILLATOR, // Ultimate Oscillator INDI_VIDYA, // Variable Index Dynamic Average diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh new file mode 100644 index 000000000..3bb9ee092 --- /dev/null +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -0,0 +1,76 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Includes. +#include "../../BufferStruct.mqh" +#include "../../Indicator.mqh" +#include "../../Storage/Objects.h" + +// Structs. +struct IndiTickMtParams : IndicatorParams { + string symbol; + // Struct constructor. + IndiTickMtParams(string _symbol = NULL, int _shift = 0) : IndicatorParams(INDI_TICK, 3, TYPE_DOUBLE) { + SetShift(_shift); + }; + IndiTickMtParams(IndiTickMtParams &_params, ENUM_TIMEFRAMES _tf) { + THIS_REF = _params; + tf = _tf; + }; + // Getters. + string GetSymbol() { return symbol; } + // Setters. + void SetSymbol(string _symbol) { symbol = _symbol; } +}; + +/** + * Price Indicator. + */ +class Indi_TickMt : public Indicator { + public: + /** + * Class constructor. + */ + Indi_TickMt(IndiTickMtParams &_p, IndicatorBase *_indi_src = NULL) : Indicator(_p, _indi_src){}; + Indi_TickMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0) : Indicator(INDI_TICK, _tf, _shift){}; + + /** + * Returns the indicator's value. + */ + virtual double GetValue(int _mode = 0, int _shift = 0) { + MqlTick _tick = SymbolInfoStatic::GetTick(_Symbol); + switch (_mode) { + case 0: + return _tick.ask; + case 1: + return _tick.bid; + case 2: +#ifdef __MQL4__ + return _tick.volume; +#else + return _tick.volume_real; +#endif + } + SetUserError(ERR_INVALID_PARAMETER); + return DBL_MAX; + } +}; diff --git a/Indicators/Tick/tests/Indi_TickMt.test.mq4 b/Indicators/Tick/tests/Indi_TickMt.test.mq4 new file mode 100644 index 000000000..091a1ba01 --- /dev/null +++ b/Indicators/Tick/tests/Indi_TickMt.test.mq4 @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Indi_Tick indicator class. + */ + +#include "Indi_TickMt.test.mq5" diff --git a/Indicators/Tick/tests/Indi_TickMt.test.mq5 b/Indicators/Tick/tests/Indi_TickMt.test.mq5 new file mode 100644 index 000000000..4c9572767 --- /dev/null +++ b/Indicators/Tick/tests/Indi_TickMt.test.mq5 @@ -0,0 +1,60 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Includes. +#include "../../../Test.mqh" +#include "../Indi_TickMt.mqh" + +/** + * @file + * Test functionality of Indi_TickMt indicator class. + */ + +Indi_TickMt indi(PERIOD_CURRENT); + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + assertTrueOrFail(indi.IsValid(), "Error on IsValid!"); + // assertTrueOrFail(indi.IsValidEntry(), "Error on IsValidEntry!"); + return (_result && _LastError == ERR_NO_ERROR ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() { + static MqlTick _tick_last; + MqlTick _tick_new = SymbolInfoStatic::GetTick(_Symbol); + if (_tick_new.time % 60 < _tick_last.time % 60) { + // Process ticks each minute. + if (_tick_new.time % 3600 < _tick_last.time % 3600) { + // Print indicator values every hour. + Print(indi.ToString()); + if (indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { + assertTrueOrExit(indi.GetEntry().IsValid(), "Invalid entry!"); + } + } + } + _tick_last = _tick_new; +} From fc5eccf0b73d2a8aa47a6ec83369dfb73af0a0aa Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 3 Nov 2021 17:21:26 +0100 Subject: [PATCH 54/97] Probably finished IndicatorDataEntry per-value type refactoring. --- Indicator.mqh | 1 - Indicator.struct.h | 11 +++++++++-- IndicatorBase.h | 28 ++++++++++++++++++---------- Indicators/Indi_AC.mqh | 1 - Indicators/Indi_AD.mqh | 1 - Indicators/Indi_Alligator.mqh | 2 +- Indicators/Indi_BWMFI.mqh | 2 +- Indicators/Indi_Envelopes.mqh | 2 +- Indicators/Indi_Killzones.mqh | 2 +- Indicators/Indi_RSI.mqh | 1 - Refs.struct.h | 10 +++++----- SerializerConverter.mqh | 8 ++++++++ tests/IndicatorsTest.mq5 | 12 +++++------- 13 files changed, 49 insertions(+), 32 deletions(-) diff --git a/Indicator.mqh b/Indicator.mqh index c99900b95..d37fc5c2a 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -966,7 +966,6 @@ class Indicator : public IndicatorBase { SetUserError(ERR_INVALID_PARAMETER); break; } - _entry.values[_mode] = GetValue(_mode, _ishift); } GetEntryAlter(_entry, _ishift); _entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry)); diff --git a/Indicator.struct.h b/Indicator.struct.h index e63f82c05..782ab22c9 100644 --- a/Indicator.struct.h +++ b/Indicator.struct.h @@ -63,7 +63,7 @@ struct IndicatorDataEntryValue { // Sets type of the value. void SetDataType(ENUM_DATATYPE _type) { - // CLearing type. + // Clearing type. flags &= 0x0F; // Setting type. @@ -142,7 +142,9 @@ struct IndicatorDataEntryValue { void Get(double &_out) { _out = value.vdbl; } void Get(float &_out) { _out = value.vflt; } void Get(int &_out) { _out = value.vint; } + void Get(unsigned int &_out) { _out = (unsigned int)value.vint; } void Get(long &_out) { _out = value.vlong; } + void Get(unsigned long &_out) { _out = (unsigned long)value.vint; } // Setters. template void Set(T _value) { @@ -377,7 +379,12 @@ struct IndicatorDataEntry { // State checkers. bool IsValid() { return CheckFlags(INDI_ENTRY_FLAG_IS_VALID); } // Serializers. - void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) { ArrayResize(values, _n1); } + void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) { + ArrayResize(values, _n1); + for (int i = 0; i < _n1; ++i) { + values[i] = (int)1; + } + } SerializerNodeType Serialize(Serializer &_s); template string ToCSV() { diff --git a/IndicatorBase.h b/IndicatorBase.h index 98def2bfc..c66861929 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -101,17 +101,24 @@ class IndicatorBase : public Chart { /** * Class constructor. */ - IndicatorBase() : indi_src(NULL) { is_fed = false; } + IndicatorBase() : indi_src(NULL) { + calc_start_bar = 0; + is_fed = false; + } /** * Class constructor. */ - IndicatorBase(ChartParams& _cparams) : indi_src(NULL), Chart(_cparams) { is_fed = false; } + IndicatorBase(ChartParams& _cparams) : indi_src(NULL), Chart(_cparams) { + calc_start_bar = 0; + is_fed = false; + } /** * Class constructor. */ IndicatorBase(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) : Chart(_tf, _symbol) { + calc_start_bar = 0; is_fed = false; indi_src = NULL; } @@ -120,6 +127,7 @@ class IndicatorBase : public Chart { * Class constructor. */ IndicatorBase(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) : Chart(_tfi, _symbol) { + calc_start_bar = 0; is_fed = false; indi_src = NULL; } @@ -988,7 +996,6 @@ class IndicatorBase : public Chart { IndicatorDataEntry _stub_entry; _stub_entry.AddFlags(_entry.GetFlags()); SerializerConverter _stub = SerializerConverter::MakeStubObject(_stub_entry, _serializer_flags, _entry.GetSize()); - return SerializerConverter::FromObject(_entry, _serializer_flags).ToString(0, &_stub); } @@ -996,23 +1003,24 @@ class IndicatorBase : public Chart { int _bars = Bars(GetSymbol(), GetTf()); if (!is_fed) { - calc_start_bar = 0; - // Calculating start_bar. - for (int i = 0; i < _bars; ++i) { - // Iterating from the oldest. - IndicatorDataEntry _entry = GetEntry(_bars - i - 1); + for (; calc_start_bar < _bars; ++calc_start_bar) { + // Iterating from the oldest or previously iterated. + IndicatorDataEntry _entry = GetEntry(_bars - calc_start_bar - 1); if (_entry.IsValid()) { // From this point we assume that future entries will be all valid. - calc_start_bar = i; is_fed = true; - return _bars - calc_start_bar; } } } + if (!is_fed) { + Print("Can't find valid bars for ", GetFullName()); + return 0; + } + // Assuming all entries are calculated (even if have invalid values). return _bars; } diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 902cc7d31..922c48574 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -33,7 +33,6 @@ double iAC(string _symbol, int _tf, int _shift) { return Indi_AC::iAC(_symbol, ( struct IndiACParams : IndicatorParams { // Struct constructor. IndiACParams(int _shift = 0) : IndicatorParams(INDI_AC, 1, TYPE_DOUBLE) { - SetDataSourceType(IDATA_ICUSTOM); SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Accelerator"); shift = _shift; diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index f94fea5a1..e03717159 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -34,7 +34,6 @@ struct IndiADParams : IndicatorParams { IndiADParams(int _shift = 0) : IndicatorParams(INDI_AD, 1, TYPE_DOUBLE) { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\AD"); - SetDataSourceType(IDATA_ICUSTOM); shift = _shift; }; IndiADParams(IndiADParams &_params, ENUM_TIMEFRAMES _tf) { diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index 77091bca5..29cd8e59e 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -165,7 +165,7 @@ class Indi_Alligator : public Indicator { #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. - return GetValue((ENUM_ALLIGATOR_LINE)1, _shift); + return GetMixedValue((ENUM_ALLIGATOR_LINE)1, _shift); } #endif double _value = EMPTY_VALUE; diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index 58057f52e..0e49dd97c 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -137,7 +137,7 @@ class Indi_BWMFI : public Indicator { #ifdef __MQL4__ // @see: https://en.wikipedia.org/wiki/Market_facilitation_index bool _vol_up = GetVolume(_shift) > GetVolume(_shift); - bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift); + bool _val_up = GetValue(BWMFI_BUFFER, _shift) > GetValue(BWMFI_BUFFER, _shift); double _histcolor = EMPTY_VALUE; switch (_vol_up) { case true: diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index 2513a7a64..152eb2e3a 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -225,7 +225,7 @@ class Indi_Envelopes : public Indicator { Indicator::GetEntryAlter(_entry); #ifdef __MQL4__ // The LINE_MAIN only exists in MQL4 for Envelopes. - _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); + _entry.values[LINE_MAIN] = GetValue((ENUM_LO_UP_LINE)LINE_MAIN, _shift); #endif } diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index 856b09475..c930ea5ab 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -106,7 +106,7 @@ class Indi_Killzones : public Indicator { /** * Returns the indicator's value. */ - float GetValue(unsigned int _mode, int _shift = 0) { + IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { float _value = FLT_MAX; int _index = (int)_mode / 2; switch (iparams.idstype) { diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index f5884612d..1433c75fb 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -289,7 +289,6 @@ class Indi_RSI : public Indicator { */ virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { double _value = EMPTY_VALUE; - int _bars_calc; double _res[]; switch (iparams.idstype) { case IDATA_BUILTIN: diff --git a/Refs.struct.h b/Refs.struct.h index 0af59cfc5..a6c3e4602 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -146,7 +146,7 @@ struct Ref { } // Dropping strong reference. if (!--ptr_object.ptr_ref_counter.num_strong_refs) { -#ifdef __debug__ +#ifdef __debug_ref__ Print(ptr_object.ptr_ref_counter.Debug()); #endif @@ -211,7 +211,7 @@ struct Ref { return Ptr(); } ++ptr_object.ptr_ref_counter.num_strong_refs; -#ifdef __debug__ +#ifdef __debug_ref__ Print(ptr_object.ptr_ref_counter.Debug()); #endif } @@ -300,7 +300,7 @@ struct WeakRef { ptr_ref_counter = _ptr.ptr_ref_counter; -#ifdef __debug__ +#ifdef __debug_ref__ Print(ptr_ref_counter.Debug()); #endif @@ -338,7 +338,7 @@ struct WeakRef { // Dropping weak reference. if (!--ptr_ref_counter.num_weak_refs) { // No more weak references. -#ifdef __debug__ +#ifdef __debug_ref__ Print(ptr_ref_counter.Debug()); #endif @@ -350,7 +350,7 @@ struct WeakRef { // Avoiding double deletion in Dynamic's destructor. ptr_ref_counter.ptr_object.ptr_ref_counter = NULL; -#ifdef __debug__ +#ifdef __debug_ref__ Print("Refs: Deleting object ", ptr_ref_counter.ptr_object); #endif diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index 37753e76d..f3c010fc8 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -47,6 +47,14 @@ class SerializerConverter { SerializerNode* Node() { return root_node; } + string ToDebugString(int _json_flags = 0) { + if (root_node == NULL) { + return ""; + } + + return root_node.ToString(_json_flags); + } + template static SerializerConverter FromObject(X& _value, int serializer_flags = SERIALIZER_FLAG_INCLUDE_ALL) { Serializer _serializer(NULL, Serialize, serializer_flags); diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 288c91edf..5c6ff58bf 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -106,15 +106,13 @@ void OnTick() { IndicatorDataEntry _entry(_indi.GetEntry()); if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { if (_entry.IsValid()) { - PrintFormat("%s: bar %d: %s", _indi.GetFullName(), bar_processed, _indi.ToString()); - // tested.Set(iter.Key(), true); // Mark as tested. - // indis.Unset(iter.Key()); - } else if (bar_processed > 20) { - DebugBreak(); + PrintFormat("%s: bar %d: %s", _indi.GetFullName(), bar_processed, _indi.ToString()); + tested.Set(iter.Key(), true); // Mark as tested. + indis.Unset(iter.Key()); + } } } } - } } /** @@ -535,7 +533,7 @@ bool InitIndicators() { } // Push white-listed indicators here. - whitelisted_indis.Push(_indi_test); + // whitelisted_indis.Push(_indi_test); return GetLastError() == ERR_NO_ERROR; } From 19ca263cc70bf1030c8754793eeb60238c12b47e Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Nov 2021 12:30:10 +0000 Subject: [PATCH 55/97] Tick/Indi_TickMt: Fixes code for new GetMixedValue() syntax --- Indicators/Tick/Indi_TickMt.mqh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index 3bb9ee092..af93a1ed6 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -56,7 +56,7 @@ class Indi_TickMt : public Indicator { /** * Returns the indicator's value. */ - virtual double GetValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { MqlTick _tick = SymbolInfoStatic::GetTick(_Symbol); switch (_mode) { case 0: From 17fac68eb0725de89d0e5d2e7abd6dee2e8f1e81 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 8 Nov 2021 11:57:21 +0100 Subject: [PATCH 56/97] TradeSignalManager will now output via ToString() all not hidden fields. --- Trade/TradeSignalManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Trade/TradeSignalManager.h b/Trade/TradeSignalManager.h index 4871e145c..e3e9060a1 100644 --- a/Trade/TradeSignalManager.h +++ b/Trade/TradeSignalManager.h @@ -177,7 +177,7 @@ class TradeSignalManager : Dynamic { */ string ToString() { // SerializerConverter _stub = SerializerConverter::MakeStubObject(SERIALIZER_FLAG_SKIP_HIDDEN); - return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_SKIP_HIDDEN) + return SerializerConverter::FromObject(THIS_REF, SERIALIZER_FLAG_INCLUDE_ALL | SERIALIZER_FLAG_SKIP_HIDDEN) .ToString(SERIALIZER_JSON_NO_WHITESPACES); } }; From 484bd829e6e28c5a60c766df86461433bde902f4 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 8 Nov 2021 15:30:26 +0100 Subject: [PATCH 57/97] Fixed Dicts to take into consideration overflow listeners. --- Dict.mqh | 22 ++++++++++++++-------- DictBase.mqh | 17 +++++++++++++++++ DictObject.mqh | 22 ++++++++++++++-------- DictStruct.mqh | 21 ++++++++++++++------- Tick/tests/TickManager.test.mq5 | 4 ++-- 5 files changed, 61 insertions(+), 25 deletions(-) diff --git a/Dict.mqh b/Dict.mqh index c5275b985..8f0801407 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -191,24 +191,30 @@ class Dict : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { - // Will resize dict if there were performance problems before. - if (allow_resize && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; - } - } - if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); - DebugBreak(); return false; } unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + if (keySlot == NULL && !IsGrowUpAllowed()) { + // Resize is prohibited. + return false; + } + + // Will resize dict if there were performance problems before. + if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); + } + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (overflow_listener != NULL) { diff --git a/DictBase.mqh b/DictBase.mqh index 534f91e8a..daeaaae7a 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -257,6 +257,18 @@ class DictBase { // No key found. } + /** + * Checks whether overflow listener allows dict to grow up. + */ + bool IsGrowUpAllowed() { + if (overflow_listener == NULL) { + return true; + } + + // Checking if overflow listener allows resize from current to higher number of slots. + return overflow_listener(DICT_OVERFLOW_REASON_FULL, Size(), 0); + } + /** * Moves last slot to given one to fill the hole after removing the value. */ @@ -280,6 +292,11 @@ class DictBase { */ const unsigned int Size() { return _DictSlots_ref._num_used; } + /** + * Returns number of all (reserved) DictSlots. + */ + const unsigned int ReservedSize() { return ArraySize(_DictSlots_ref.DictSlots); } + /** * Checks whether given key exists in the dictionary. */ diff --git a/DictObject.mqh b/DictObject.mqh index 3585c1972..2c828d3c1 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -178,24 +178,30 @@ class DictObject : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - // Will resize dict if there were performance problems before. - if (allow_resize && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; - } - } - if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); - DebugBreak(); return false; } unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + if (keySlot == NULL && !IsGrowUpAllowed()) { + // Resize is prohibited. + return false; + } + + // Will resize dict if there were performance problems before. + if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); + } + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (overflow_listener != NULL) { diff --git a/DictStruct.mqh b/DictStruct.mqh index f9d33c15d..bfbd65b99 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -221,13 +221,6 @@ class DictStruct : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - // Will resize dict if there were performance problems before. - if (allow_resize && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; - } - } - if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { @@ -238,6 +231,20 @@ class DictStruct : public DictBase { unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + if (keySlot == NULL && !IsGrowUpAllowed()) { + // Resize is prohibited. + return false; + } + + // Will resize dict if there were performance problems before. + if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); + } + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (overflow_listener != NULL) { diff --git a/Tick/tests/TickManager.test.mq5 b/Tick/tests/TickManager.test.mq5 index 8bb7b1fa2..a2b36637a 100644 --- a/Tick/tests/TickManager.test.mq5 +++ b/Tick/tests/TickManager.test.mq5 @@ -47,7 +47,7 @@ void OnTick() { ::SymbolInfoTick(_Symbol, tick); tm.Add(tick, tick.time); if (tick.time % 3600 == 0) { - PrintFormat("Ticks: %d; Memory %d/%d", tm.Size(), ::TerminalInfoInteger(TERMINAL_MEMORY_USED), - ::TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)); + PrintFormat("Ticks: %d (reserved %d); Memory %d/%d", tm.Size(), tm.ReservedSize(), + ::TerminalInfoInteger(TERMINAL_MEMORY_USED), ::TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)); } } From 47e353f1dc5c6a108b153c4ddd93c513d800e225 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Nov 2021 14:11:23 +0000 Subject: [PATCH 58/97] Indicator: Renames GetMixedValue to GetEntryValue --- Indicator.mqh | 6 ++++-- IndicatorBase.h | 6 ++---- Indicators/Bitwise/Indi_Candle.mqh | 13 +++++++------ Indicators/Bitwise/Indi_Pattern.mqh | 13 +++++++------ Indicators/Indi_AC.mqh | 7 ++++--- Indicators/Indi_AD.mqh | 7 ++++--- Indicators/Indi_ADX.mqh | 8 +++++--- Indicators/Indi_ADXW.mqh | 7 ++++--- Indicators/Indi_AMA.mqh | 7 ++++--- Indicators/Indi_AO.mqh | 7 ++++--- Indicators/Indi_ASI.mqh | 7 ++++--- Indicators/Indi_ATR.mqh | 7 ++++--- Indicators/Indi_Alligator.mqh | 11 ++++++----- Indicators/Indi_AppliedPrice.mqh | 5 +++-- Indicators/Indi_BWMFI.mqh | 7 ++++--- Indicators/Indi_BWZT.mqh | 7 ++++--- Indicators/Indi_Bands.mqh | 9 +++++---- Indicators/Indi_BearsPower.mqh | 7 ++++--- Indicators/Indi_BullsPower.mqh | 7 ++++--- Indicators/Indi_CCI.mqh | 11 ++++++----- Indicators/Indi_CHO.mqh | 7 ++++--- Indicators/Indi_CHV.mqh | 7 ++++--- Indicators/Indi_ColorBars.mqh | 7 ++++--- Indicators/Indi_ColorCandlesDaily.mqh | 7 ++++--- Indicators/Indi_ColorLine.mqh | 7 ++++--- Indicators/Indi_CustomMovingAverage.mqh | 5 +++-- Indicators/Indi_DEMA.mqh | 9 +++++---- Indicators/Indi_DeMarker.mqh | 7 ++++--- Indicators/Indi_Demo.mqh | 7 ++++--- Indicators/Indi_DetrendedPrice.mqh | 7 ++++--- Indicators/Indi_Drawer.mqh | 7 ++++--- Indicators/Indi_Envelopes.mqh | 10 ++++++---- Indicators/Indi_Force.mqh | 7 ++++--- Indicators/Indi_FractalAdaptiveMA.mqh | 7 ++++--- Indicators/Indi_Fractals.mqh | 7 ++++--- Indicators/Indi_Gator.mqh | 7 ++++--- Indicators/Indi_HeikenAshi.mqh | 9 +++++---- Indicators/Indi_Ichimoku.mqh | 11 ++++++----- Indicators/Indi_Killzones.mqh | 5 +++-- Indicators/Indi_MA.mqh | 11 ++++++----- Indicators/Indi_MACD.mqh | 7 ++++--- Indicators/Indi_MFI.mqh | 9 +++++---- Indicators/Indi_MassIndex.mqh | 8 +++++--- Indicators/Indi_Momentum.mqh | 7 ++++--- Indicators/Indi_OBV.mqh | 9 +++++---- Indicators/Indi_OsMA.mqh | 7 ++++--- Indicators/Indi_Pivot.mqh | 5 ++++- Indicators/Indi_PriceChannel.mqh | 10 ++++------ Indicators/Indi_PriceFeeder.mqh | 7 ++++--- Indicators/Indi_PriceVolumeTrend.mqh | 7 ++++--- Indicators/Indi_RS.mqh | 5 +++-- Indicators/Indi_RSI.mqh | 10 ++++++---- Indicators/Indi_RVI.mqh | 7 ++++--- Indicators/Indi_RateOfChange.mqh | 7 ++++--- Indicators/Indi_SAR.mqh | 7 ++++--- Indicators/Indi_StdDev.mqh | 9 +++++---- Indicators/Indi_Stochastic.mqh | 7 ++++--- Indicators/Indi_TEMA.mqh | 7 ++++--- Indicators/Indi_TRIX.mqh | 9 +++++---- Indicators/Indi_UltimateOscillator.mqh | 7 ++++--- Indicators/Indi_VIDYA.mqh | 7 ++++--- Indicators/Indi_VROC.mqh | 7 ++++--- Indicators/Indi_Volumes.mqh | 7 ++++--- Indicators/Indi_WPR.mqh | 7 ++++--- Indicators/Indi_WilliamsAD.mqh | 7 ++++--- Indicators/Indi_ZigZag.mqh | 7 ++++--- Indicators/Indi_ZigZagColor.mqh | 11 +++++------ Indicators/OHLC/Indi_OHLC.mqh | 5 +++-- Indicators/Price/Indi_Price.mqh | 5 +++-- Indicators/Special/Indi_Math.mqh | 7 ++++--- Indicators/Tick/Indi_TickMt.mqh | 3 ++- tests/DrawIndicatorTest.mq5 | 7 +------ tests/IndicatorsTest.mq5 | 2 +- 73 files changed, 304 insertions(+), 239 deletions(-) diff --git a/Indicator.mqh b/Indicator.mqh index d37fc5c2a..b2e6171b7 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -1002,8 +1002,9 @@ class Indicator : public IndicatorBase { * @return * Returns DataParamEntry struct filled with a single value. */ - virtual DataParamEntry GetEntryValue(int _shift = -1, int _mode = 0) { - IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : iparams.GetShift()); + /* + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + IndicatorDataEntry _entry = GetEntry(fmax(_shift, _shift >= 0 ? _shift : iparams.GetShift())); DataParamEntry _value_entry; switch (iparams.GetDataValueType()) { case TYPE_BOOL: @@ -1034,6 +1035,7 @@ class Indicator : public IndicatorBase { } return _value_entry; } + */ /** * Returns the indicator's value. diff --git a/IndicatorBase.h b/IndicatorBase.h index 5e30d4dd7..69081ff71 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -873,12 +873,10 @@ class IndicatorBase : public Chart { template T GetValue(int _shift = 0, int _mode = 0) { T _out; - GetMixedValue(_shift, _mode).Get(_out); + GetEntryValue(_shift, _mode).Get(_out); return _out; } - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) = NULL; - /** * Returns price corresponding to indicator value for a given shift and mode. * @@ -967,7 +965,7 @@ class IndicatorBase : public Chart { /** * Returns the indicator's entry value. */ - virtual DataParamEntry GetEntryValue(int _shift = -1, int _mode = 0) = NULL; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) = NULL; /** * Returns indicator value for a given shift and mode. diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index 0ff594c0d..a9b94aea1 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -66,14 +66,15 @@ class Indi_Candle : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); BarOHLC _ohlcs[1]; switch (iparams.idstype) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. - _ohlcs[0] = Chart::GetOHLC(_shift); + _ohlcs[0] = Chart::GetOHLC(_ishift); break; case IDATA_INDICATOR: // In this mode, price is fetched from given indicator. Such indicator @@ -92,10 +93,10 @@ class Indi_Candle : public Indicator { break; } - _ohlcs[0].open = GetDataSource().GetValue(_shift, PRICE_OPEN); - _ohlcs[0].high = GetDataSource().GetValue(_shift, PRICE_HIGH); - _ohlcs[0].low = GetDataSource().GetValue(_shift, PRICE_LOW); - _ohlcs[0].close = GetDataSource().GetValue(_shift, PRICE_CLOSE); + _ohlcs[0].open = GetDataSource().GetValue(_ishift, PRICE_OPEN); + _ohlcs[0].high = GetDataSource().GetValue(_ishift, PRICE_HIGH); + _ohlcs[0].low = GetDataSource().GetValue(_ishift, PRICE_LOW); + _ohlcs[0].close = GetDataSource().GetValue(_ishift, PRICE_CLOSE); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index ed0d71f6d..f9e014ec0 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -57,15 +57,16 @@ class Indi_Pattern : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int i; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); BarOHLC _ohlcs[8]; switch (iparams.idstype) { case IDATA_BUILTIN: // In this mode, price is fetched from chart. for (i = 0; i < iparams.GetMaxModes(); ++i) { - _ohlcs[i] = Chart::GetOHLC(_shift + i); + _ohlcs[i] = Chart::GetOHLC(_ishift + i); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return WRONG_VALUE; @@ -90,10 +91,10 @@ class Indi_Pattern : public Indicator { } for (i = 0; i < iparams.GetMaxModes(); ++i) { - _ohlcs[i].open = GetDataSource().GetValue(_shift + i, PRICE_OPEN); - _ohlcs[i].high = GetDataSource().GetValue(_shift + i, PRICE_HIGH); - _ohlcs[i].low = GetDataSource().GetValue(_shift + i, PRICE_LOW); - _ohlcs[i].close = GetDataSource().GetValue(_shift + i, PRICE_CLOSE); + _ohlcs[i].open = GetDataSource().GetValue(_ishift + i, PRICE_OPEN); + _ohlcs[i].high = GetDataSource().GetValue(_ishift + i, PRICE_HIGH); + _ohlcs[i].low = GetDataSource().GetValue(_ishift + i, PRICE_LOW); + _ohlcs[i].close = GetDataSource().GetValue(_ishift + i, PRICE_CLOSE); if (!_ohlcs[i].IsValid()) { // Return empty entry on invalid candles. return WRONG_VALUE; diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index 5e9fb260e..be9fe709b 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -100,15 +100,16 @@ class Indi_AC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { IndicatorDataEntryValue _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AC::iAC(GetSymbol(), GetTf(), _shift, THIS_PTR); + _value = Indi_AC::iAC(GetSymbol(), GetTf(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AD.mqh b/Indicators/Indi_AD.mqh index e2fcf2d5e..51ea677cf 100644 --- a/Indicators/Indi_AD.mqh +++ b/Indicators/Indi_AD.mqh @@ -101,15 +101,16 @@ class Indi_AD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AD::iAD(GetSymbol(), GetTf(), _shift, THIS_PTR); + _value = Indi_AD::iAD(GetSymbol(), GetTf(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ADX.mqh b/Indicators/Indi_ADX.mqh index a403d961d..752805800 100644 --- a/Indicators/Indi_ADX.mqh +++ b/Indicators/Indi_ADX.mqh @@ -115,19 +115,21 @@ class Indi_ADX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _shift, THIS_PTR); + _value = Indi_ADX::iADX(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); + break; } return _value; } diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh index 6ac3565d7..efd22ce2e 100644 --- a/Indicators/Indi_ADXW.mqh +++ b/Indicators/Indi_ADXW.mqh @@ -215,16 +215,17 @@ class Indi_ADXW : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN_ADX, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN_ADX, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ADXW::iADXWilder(GetSymbol(), GetTf(), GetPeriod(), _mode, _shift, THIS_PTR); + _value = Indi_ADXW::iADXWilder(GetSymbol(), GetTf(), GetPeriod(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh index ceb65c602..58a8bee10 100644 --- a/Indicators/Indi_AMA.mqh +++ b/Indicators/Indi_AMA.mqh @@ -199,16 +199,17 @@ class Indi_AMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), - GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); + GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _shift); + GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh index 6b494132e..a88552202 100644 --- a/Indicators/Indi_AO.mqh +++ b/Indicators/Indi_AO.mqh @@ -103,15 +103,16 @@ class Indi_AO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_AO::iAO(GetSymbol(), GetTf(), _shift, _mode, THIS_PTR); + _value = Indi_AO::iAO(GetSymbol(), GetTf(), _ishift, _mode, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ASI.mqh b/Indicators/Indi_ASI.mqh index 953691830..2e0cf341b 100644 --- a/Indicators/Indi_ASI.mqh +++ b/Indicators/Indi_ASI.mqh @@ -155,18 +155,19 @@ class Indi_ASI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetMaximumPriceChanging() /*]*/, 0, _shift); + /*[*/ GetMaximumPriceChanging() /*]*/, 0, _ishift); break; case IDATA_ONCALCULATE: { INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(GetSymbol(), GetTf(), Util::MakeKey("Indi_ASI", GetMaximumPriceChanging())); _value = - iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, GetMaximumPriceChanging(), _mode, _shift, _cache); + iASIOnArray(INDICATOR_CALCULATE_POPULATED_PARAMS_LONG, GetMaximumPriceChanging(), _mode, _ishift, _cache); break; } default: diff --git a/Indicators/Indi_ATR.mqh b/Indicators/Indi_ATR.mqh index e792d52a0..c74f1edd6 100644 --- a/Indicators/Indi_ATR.mqh +++ b/Indicators/Indi_ATR.mqh @@ -103,15 +103,16 @@ class Indi_ATR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); + _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Alligator.mqh b/Indicators/Indi_Alligator.mqh index afccb5ff6..62b552df7 100644 --- a/Indicators/Indi_Alligator.mqh +++ b/Indicators/Indi_Alligator.mqh @@ -162,20 +162,21 @@ class Indi_Alligator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { + double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); #ifdef __MQL4__ if (_mode == 0) { // In MQL4 mode 0 should be treated as mode 1 as Alligator buffers starts from index 1. - return GetMixedValue((ENUM_ALLIGATOR_LINE)1, _shift); + return GetEntryValue((ENUM_ALLIGATOR_LINE)1, _ishift); } #endif - double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_Alligator::iAlligator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), - GetAppliedPrice(), (ENUM_ALLIGATOR_LINE)_mode, _shift, THIS_PTR); + GetAppliedPrice(), (ENUM_ALLIGATOR_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ @@ -183,7 +184,7 @@ class Indi_Alligator : public Indicator { GetLipsShift(), GetMAMethod(), GetAppliedPrice() /*]*/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_AppliedPrice.mqh b/Indicators/Indi_AppliedPrice.mqh index f4d875ddb..379596331 100644 --- a/Indicators/Indi_AppliedPrice.mqh +++ b/Indicators/Indi_AppliedPrice.mqh @@ -74,15 +74,16 @@ class Indi_AppliedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_INDICATOR: if (HasDataSource()) { // Future validation of indi_src will check if we set mode for source indicator // (e.g. for applied price of Indi_Price). iparams.SetDataSourceMode(GetAppliedPrice()); - _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), _shift); + _value = Indi_AppliedPrice::iAppliedPriceOnIndicator(GetDataSource(), GetAppliedPrice(), _ishift); } break; default: diff --git a/Indicators/Indi_BWMFI.mqh b/Indicators/Indi_BWMFI.mqh index a0216a332..cc8b55e08 100644 --- a/Indicators/Indi_BWMFI.mqh +++ b/Indicators/Indi_BWMFI.mqh @@ -114,16 +114,17 @@ class Indi_BWMFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = BWMFI_BUFFER, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BWMFI_BUFFER, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _shift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); + _value = Indi_BWMFI::iBWMFI(GetSymbol(), GetTf(), _ishift, (ENUM_BWMFI_BUFFER)_mode, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_BWZT.mqh b/Indicators/Indi_BWZT.mqh index e03857648..65d7cb881 100644 --- a/Indicators/Indi_BWZT.mqh +++ b/Indicators/Indi_BWZT.mqh @@ -172,14 +172,15 @@ class Indi_BWZT : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Bands.mqh b/Indicators/Indi_Bands.mqh index ee085c44b..0ff6a92e1 100644 --- a/Indicators/Indi_Bands.mqh +++ b/Indicators/Indi_Bands.mqh @@ -239,22 +239,23 @@ class Indi_Bands : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = BAND_BASE, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = BAND_BASE, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), - GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); + GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _shift); + GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _ishift); break; case IDATA_INDICATOR: // Calculating bands value from specified indicator. _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), - GetBandsShift(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR); + GetBandsShift(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR); break; } return _value; diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh index d27567064..1b9721606 100644 --- a/Indicators/Indi_BearsPower.mqh +++ b/Indicators/Indi_BearsPower.mqh @@ -104,16 +104,17 @@ class Indi_BearsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); + _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh index 9d0bbabe7..1741f8da7 100644 --- a/Indicators/Indi_BullsPower.mqh +++ b/Indicators/Indi_BullsPower.mqh @@ -104,16 +104,17 @@ class Indi_BullsPower : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR); + _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh index a0362f867..c32d4c191 100644 --- a/Indicators/Indi_CCI.mqh +++ b/Indicators/Indi_CCI.mqh @@ -145,25 +145,26 @@ class Indi_CCI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = - Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _shift /* + iparams.shift*/, THIS_PTR); + _value = Indi_CCI::iCCI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift /* + iparams.shift*/, + THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetAppliedPrice() /* ] */, 0, _shift); + GetAppliedPrice() /* ] */, 0, _ishift); break; case IDATA_INDICATOR: ValidateSelectedDataSource(); // @fixit Somehow shift isn't used neither in MT4 nor MT5. _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDataSourceMode(), - _shift /* + iparams.shift*/); + _ishift /* + iparams.shift*/); break; } return _value; diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh index 16fe50ea1..1cf24699e 100644 --- a/Indicators/Indi_CHO.mqh +++ b/Indicators/Indi_CHO.mqh @@ -166,16 +166,17 @@ class Indi_CHO : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_CHO::iChaikin(GetSymbol(), GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(), - GetInputVolume() /*]*/, _mode, _shift, THIS_PTR); + GetInputVolume() /*]*/, _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(), - GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _shift); + GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh index ea7b34bc5..d3f97fd42 100644 --- a/Indicators/Indi_CHV.mqh +++ b/Indicators/Indi_CHV.mqh @@ -162,16 +162,17 @@ class Indi_CHV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_CHV::iCHV(GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/, - _mode, _shift, THIS_PTR); + _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), - GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _shift); + GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh index 056dcf04f..f89773c19 100644 --- a/Indicators/Indi_ColorBars.mqh +++ b/Indicators/Indi_ColorBars.mqh @@ -113,14 +113,15 @@ class Indi_ColorBars : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorCandlesDaily.mqh b/Indicators/Indi_ColorCandlesDaily.mqh index 31fc381c8..b8c4b851c 100644 --- a/Indicators/Indi_ColorCandlesDaily.mqh +++ b/Indicators/Indi_ColorCandlesDaily.mqh @@ -110,14 +110,15 @@ class Indi_ColorCandlesDaily : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ColorLine.mqh b/Indicators/Indi_ColorLine.mqh index 51ed0d7e9..d3dd60ed7 100644 --- a/Indicators/Indi_ColorLine.mqh +++ b/Indicators/Indi_ColorLine.mqh @@ -172,14 +172,15 @@ class Indi_ColorLine : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_CustomMovingAverage.mqh b/Indicators/Indi_CustomMovingAverage.mqh index 2c801b9bb..7d83ee7dc 100644 --- a/Indicators/Indi_CustomMovingAverage.mqh +++ b/Indicators/Indi_CustomMovingAverage.mqh @@ -67,12 +67,13 @@ class Indi_CustomMovingAverage : public Indicator /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(), - GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _shift); + GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh index 2d91c0934..420034607 100644 --- a/Indicators/Indi_DEMA.mqh +++ b/Indicators/Indi_DEMA.mqh @@ -166,26 +166,27 @@ class Indi_DEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: // We're getting DEMA from Price indicator. istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_DEMA::iDEMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetAppliedPrice(), _shift, _mode, + _value = Indi_DEMA::iDEMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetAppliedPrice(), _ishift, _mode, GetPointer(this)); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(), - GetAppliedPrice() /*]*/, _mode, _shift); + GetAppliedPrice() /*]*/, _mode, _ishift); break; case IDATA_INDICATOR: // Calculating DEMA value from specified indicator. _value = Indi_DEMA::iDEMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), GetPeriod(), - GetMAShift(), _shift); + GetMAShift(), _ishift); break; } return _value; diff --git a/Indicators/Indi_DeMarker.mqh b/Indicators/Indi_DeMarker.mqh index 81a1e657e..98524dcdb 100644 --- a/Indicators/Indi_DeMarker.mqh +++ b/Indicators/Indi_DeMarker.mqh @@ -102,16 +102,17 @@ class Indi_DeMarker : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); + _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh index 4f482b3b5..a5bf323d5 100644 --- a/Indicators/Indi_Demo.mqh +++ b/Indicators/Indi_Demo.mqh @@ -72,10 +72,11 @@ class Indi_Demo : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { - double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _shift, THIS_PTR); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + double _value = Indi_Demo::iDemo(GetSymbol(), GetTf(), _ishift, THIS_PTR); if (iparams.is_draw) { - draw.DrawLineTo(GetName(), GetBarTime(_shift), _value); + draw.DrawLineTo(GetName(), GetBarTime(_ishift), _value); } return _value; } diff --git a/Indicators/Indi_DetrendedPrice.mqh b/Indicators/Indi_DetrendedPrice.mqh index b2836d80c..b8c4fe1cd 100644 --- a/Indicators/Indi_DetrendedPrice.mqh +++ b/Indicators/Indi_DetrendedPrice.mqh @@ -116,16 +116,17 @@ class Indi_DetrendedPrice : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_DetrendedPrice::iDPO(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, - _shift, THIS_PTR); + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 85d74f98b..2fc3c2593 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -172,15 +172,16 @@ class Indi_Drawer : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _shift, THIS_PTR); + _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _ishift, THIS_PTR); break; case IDATA_INDICATOR: - _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), _shift); + _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Envelopes.mqh b/Indicators/Indi_Envelopes.mqh index a3173c8a7..4761ab8ce 100644 --- a/Indicators/Indi_Envelopes.mqh +++ b/Indicators/Indi_Envelopes.mqh @@ -197,25 +197,27 @@ class Indi_Envelopes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(), - GetAppliedPrice(), GetDeviation(), _mode, _shift, THIS_PTR); + GetAppliedPrice(), GetDeviation(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(), - GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _shift); + GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _ishift); break; case IDATA_INDICATOR: _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetDataSourceMode(), GetMAShift(), GetDeviation(), - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); + break; } return _value; } diff --git a/Indicators/Indi_Force.mqh b/Indicators/Indi_Force.mqh index a592684f0..9e047338b 100644 --- a/Indicators/Indi_Force.mqh +++ b/Indicators/Indi_Force.mqh @@ -117,17 +117,18 @@ class Indi_Force : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = - Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _shift, THIS_PTR); + Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, _shift); + GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_FractalAdaptiveMA.mqh b/Indicators/Indi_FractalAdaptiveMA.mqh index 6f2d90889..7640170c0 100644 --- a/Indicators/Indi_FractalAdaptiveMA.mqh +++ b/Indicators/Indi_FractalAdaptiveMA.mqh @@ -134,16 +134,17 @@ class Indi_FrAMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_FrAMA::iFrAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFRAMAShift(), GetAppliedPrice() /*]*/, - _mode, _shift, THIS_PTR); + _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetFRAMAShift() /*]*/, 0, _shift); + GetFRAMAShift() /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Fractals.mqh b/Indicators/Indi_Fractals.mqh index c7c47158c..49d395311 100644 --- a/Indicators/Indi_Fractals.mqh +++ b/Indicators/Indi_Fractals.mqh @@ -102,15 +102,16 @@ class Indi_Fractals : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _shift, THIS_PTR); + _value = _value = Indi_Fractals::iFractals(GetSymbol(), GetTf(), (ENUM_LO_UP_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Gator.mqh b/Indicators/Indi_Gator.mqh index 561b712f5..9dca4b882 100644 --- a/Indicators/Indi_Gator.mqh +++ b/Indicators/Indi_Gator.mqh @@ -169,14 +169,15 @@ class Indi_Gator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_Gator::iGator(GetSymbol(), GetTf(), GetJawPeriod(), GetJawShift(), GetTeethPeriod(), GetTeethShift(), GetLipsPeriod(), GetLipsShift(), GetMAMethod(), GetAppliedPrice(), - (ENUM_GATOR_HISTOGRAM)_mode, _shift, THIS_PTR); + (ENUM_GATOR_HISTOGRAM)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ @@ -184,7 +185,7 @@ class Indi_Gator : public Indicator { GetLipsShift(), GetMAMethod(), GetAppliedPrice() /**/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_HeikenAshi.mqh b/Indicators/Indi_HeikenAshi.mqh index 30bbd751a..789478852 100644 --- a/Indicators/Indi_HeikenAshi.mqh +++ b/Indicators/Indi_HeikenAshi.mqh @@ -195,8 +195,9 @@ class Indi_HeikenAshi : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = HA_OPEN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = HA_OPEN, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: #ifdef __MQL4__ @@ -216,15 +217,15 @@ class Indi_HeikenAshi : public Indicator { break; } #endif - _value = Indi_HeikenAshi::iHeikenAshi(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_HeikenAshi::iHeikenAshi(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, _ishift); break; case IDATA_ICUSTOM_LEGACY: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_HeikenAshi::iCustomLegacyHeikenAshi(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), _mode, - _shift, THIS_PTR); + _ishift, THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Ichimoku.mqh b/Indicators/Indi_Ichimoku.mqh index 504a7adc2..0f381d8d5 100644 --- a/Indicators/Indi_Ichimoku.mqh +++ b/Indicators/Indi_Ichimoku.mqh @@ -142,17 +142,18 @@ class Indi_Ichimoku : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_Ichimoku::iIchimoku(GetSymbol(), GetTf(), GetTenkanSen(), GetKijunSen(), GetSenkouSpanB(), _mode, - _shift, THIS_PTR); + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetTenkanSen(), - GetKijunSen(), GetSenkouSpanB() /*]*/, _mode, _shift); + GetKijunSen(), GetSenkouSpanB() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); @@ -168,9 +169,9 @@ class Indi_Ichimoku : public Indicator { #ifdef __MQL4__ // In MQL4 value of LINE_TENKANSEN is 1 (not 0 as in MQL5), // so we are duplicating it. - _entry.values[0] = GetMixedValue(LINE_TENKANSEN, _shift); + _entry.values[0] = GetEntryValue(LINE_TENKANSEN, _shift); #endif - _entry.values[LINE_CHIKOUSPAN] = GetMixedValue(LINE_CHIKOUSPAN, _shift + 26); + _entry.values[LINE_CHIKOUSPAN] = GetEntryValue(LINE_CHIKOUSPAN, _shift + 26); } /** diff --git a/Indicators/Indi_Killzones.mqh b/Indicators/Indi_Killzones.mqh index c930ea5ab..70016b6db 100644 --- a/Indicators/Indi_Killzones.mqh +++ b/Indicators/Indi_Killzones.mqh @@ -106,9 +106,10 @@ class Indi_Killzones : public Indicator { /** * Returns the indicator's value. */ - IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { float _value = FLT_MAX; int _index = (int)_mode / 2; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: // Builtin mode not supported. @@ -118,7 +119,7 @@ class Indi_Killzones : public Indicator { ikt.Set(::TimeGMT()); if (ikt.CheckHours(_index)) { // Pass values to check for new highs or lows. - ikt.Update(_mode % 2 == 0 ? (float)GetHigh(_shift) : (float)GetLow(_shift), _index); + ikt.Update(_mode % 2 == 0 ? (float)GetHigh(_ishift) : (float)GetLow(_ishift), _index); } // Set a final value. _value = _mode % 2 == 0 ? ikt.GetHigh(_index) : ikt.GetLow(_index); diff --git a/Indicators/Indi_MA.mqh b/Indicators/Indi_MA.mqh index 5dfbba5eb..d8ec96e68 100644 --- a/Indicators/Indi_MA.mqh +++ b/Indicators/Indi_MA.mqh @@ -627,23 +627,24 @@ class Indi_MA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), _shift, - THIS_PTR); + _value = Indi_MA::iMA(GetSymbol(), GetTf(), GetPeriod(), GetMAShift(), GetMAMethod(), GetAppliedPrice(), + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(), - GetMAShift(), GetMAMethod(), GetAppliedPrice() /* ] */, 0, _shift); + GetMAShift(), GetMAMethod(), GetAppliedPrice() /* ] */, 0, _ishift); break; case IDATA_INDICATOR: // Calculating MA value from specified indicator. _value = Indi_MA::iMAOnIndicator(GetCache(), GetDataSource(), GetDataSourceMode(), GetSymbol(), GetTf(), - GetPeriod(), GetMAShift(), GetMAMethod(), _shift); + GetPeriod(), GetMAShift(), GetMAMethod(), _ishift); break; } return _value; diff --git a/Indicators/Indi_MACD.mqh b/Indicators/Indi_MACD.mqh index a440c8ad4..64570f79b 100644 --- a/Indicators/Indi_MACD.mqh +++ b/Indicators/Indi_MACD.mqh @@ -114,18 +114,19 @@ class Indi_MACD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_MACD::iMACD(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), - GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); + GetAppliedPrice(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _shift); + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_MFI.mqh b/Indicators/Indi_MFI.mqh index 0c27f09f6..902d6d08b 100644 --- a/Indicators/Indi_MFI.mqh +++ b/Indicators/Indi_MFI.mqh @@ -111,20 +111,21 @@ class Indi_MFI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; #ifdef __MQL4__ - _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _shift); + _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), _ishift); #else // __MQL5__ - _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), _shift, THIS_PTR); + _value = Indi_MFI::iMFI(GetSymbol(), GetTf(), GetPeriod(), GetAppliedVolume(), _ishift, THIS_PTR); #endif break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - VOLUME_TICK /*]*/, 0, _shift); + VOLUME_TICK /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_MassIndex.mqh b/Indicators/Indi_MassIndex.mqh index 8df1fb995..817b81cd8 100644 --- a/Indicators/Indi_MassIndex.mqh +++ b/Indicators/Indi_MassIndex.mqh @@ -153,19 +153,21 @@ class Indi_MassIndex : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_MassIndex::iMI(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetSecondPeriod(), GetSumPeriod() /*]*/, - _mode, _shift, THIS_PTR); + _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _shift); + GetSecondPeriod(), GetSumPeriod() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); + break; } return _value; } diff --git a/Indicators/Indi_Momentum.mqh b/Indicators/Indi_Momentum.mqh index 3a2c2cc32..5f4266dd0 100644 --- a/Indicators/Indi_Momentum.mqh +++ b/Indicators/Indi_Momentum.mqh @@ -141,18 +141,19 @@ class Indi_Momentum : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; // @fixit Somehow shift isn't used neither in MT4 nor MT5. - _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _shift, + _value = Indi_Momentum::iMomentum(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), iparams.shift + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; case IDATA_INDICATOR: ValidateSelectedDataSource(); diff --git a/Indicators/Indi_OBV.mqh b/Indicators/Indi_OBV.mqh index 96ef284df..cefa485e9 100644 --- a/Indicators/Indi_OBV.mqh +++ b/Indicators/Indi_OBV.mqh @@ -118,20 +118,21 @@ class Indi_OBV : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; #ifdef __MQL4__ - _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _shift); + _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedPrice(), _ishift); #else // __MQL5__ - _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), _shift, THIS_PTR); + _value = Indi_OBV::iOBV(GetSymbol(), GetTf(), GetAppliedVolume(), _ishift, THIS_PTR); #endif break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_OsMA.mqh b/Indicators/Indi_OsMA.mqh index cd6c7a8e4..ac0a608a7 100644 --- a/Indicators/Indi_OsMA.mqh +++ b/Indicators/Indi_OsMA.mqh @@ -111,18 +111,19 @@ class Indi_OsMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); double _value = EMPTY_VALUE; switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_OsMA::iOsMA(GetSymbol(), GetTf(), GetEmaFastPeriod(), GetEmaSlowPeriod(), GetSignalPeriod(), - GetAppliedPrice(), _shift, THIS_PTR); + GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetEmaFastPeriod(), - GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _shift); + GetEmaSlowPeriod(), GetSignalPeriod(), GetAppliedPrice() /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Pivot.mqh b/Indicators/Indi_Pivot.mqh index 586e15f9c..fd4c7cf4d 100644 --- a/Indicators/Indi_Pivot.mqh +++ b/Indicators/Indi_Pivot.mqh @@ -100,7 +100,10 @@ class Indi_Pivot : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { return GetEntry(_shift)[_mode]; } + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + return GetEntry(_ishift)[_mode]; + } /** * Checks if indicator entry values are valid. diff --git a/Indicators/Indi_PriceChannel.mqh b/Indicators/Indi_PriceChannel.mqh index c5513fa72..0afc2392e 100644 --- a/Indicators/Indi_PriceChannel.mqh +++ b/Indicators/Indi_PriceChannel.mqh @@ -106,22 +106,20 @@ class Indi_PriceChannel : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { - ResetLastError(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_PriceChannel::iPriceChannel(GetSymbol(), GetTf(), GetPeriod(), _mode, _shift, THIS_PTR); + _value = Indi_PriceChannel::iPriceChannel(GetSymbol(), GetTf(), GetPeriod(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); } - istate.is_ready = _LastError == ERR_NO_ERROR; - istate.is_changed = false; return _value; } diff --git a/Indicators/Indi_PriceFeeder.mqh b/Indicators/Indi_PriceFeeder.mqh index e88ed67fc..c1d286d88 100644 --- a/Indicators/Indi_PriceFeeder.mqh +++ b/Indicators/Indi_PriceFeeder.mqh @@ -75,12 +75,13 @@ class Indi_PriceFeeder : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { int data_size = ArraySize(iparams.price_data); + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); - if (_shift >= data_size || _shift < 0) return DBL_MIN; + if (_ishift >= data_size || _ishift < 0) return DBL_MIN; - double _value = iparams.price_data[data_size - _shift - 1]; + double _value = iparams.price_data[data_size - _ishift - 1]; return _value; } diff --git a/Indicators/Indi_PriceVolumeTrend.mqh b/Indicators/Indi_PriceVolumeTrend.mqh index f96c37dc5..17505eff1 100644 --- a/Indicators/Indi_PriceVolumeTrend.mqh +++ b/Indicators/Indi_PriceVolumeTrend.mqh @@ -121,16 +121,17 @@ class Indi_PriceVolumeTrend : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = - Indi_PriceVolumeTrend::iPVT(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); + Indi_PriceVolumeTrend::iPVT(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetAppliedVolume() /*]*/, 0, _shift); + /*[*/ GetAppliedVolume() /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_RS.mqh b/Indicators/Indi_RS.mqh index 4e71dd17c..51c03ed8d 100644 --- a/Indicators/Indi_RS.mqh +++ b/Indicators/Indi_RS.mqh @@ -78,10 +78,11 @@ class Indi_RS : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_MATH: - return imath[_mode].Ptr().GetMixedValue(); + return imath[_mode].Ptr().GetEntryValue(); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_RSI.mqh b/Indicators/Indi_RSI.mqh index 895c13e54..41b7339a9 100644 --- a/Indicators/Indi_RSI.mqh +++ b/Indicators/Indi_RSI.mqh @@ -289,23 +289,25 @@ class Indi_RSI : public Indicator { * Note that in MQL5 Applied Price must be passed as the last parameter * (before mode and shift). */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; double _res[]; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _shift, THIS_PTR); + _value = + Indi_RSI::iRSI(GetSymbol(), GetTf(), iparams.GetPeriod(), iparams.GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ iparams.GetPeriod(), - iparams.GetAppliedPrice() /* ] */, 0, _shift); + iparams.GetAppliedPrice() /* ] */, 0, _ishift); Print(_value); break; case IDATA_INDICATOR: _value = Indi_RSI::iRSIOnIndicator(GetDataSource(), THIS_PTR, GetSymbol(), GetTf(), iparams.GetPeriod(), - iparams.GetAppliedPrice(), _shift); + iparams.GetAppliedPrice(), _ishift); break; } return _value; diff --git a/Indicators/Indi_RVI.mqh b/Indicators/Indi_RVI.mqh index 93967b54a..18402acad 100644 --- a/Indicators/Indi_RVI.mqh +++ b/Indicators/Indi_RVI.mqh @@ -103,16 +103,17 @@ class Indi_RVI : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _shift, THIS_PTR); + _value = Indi_RVI::iRVI(GetSymbol(), GetTf(), GetPeriod(), (ENUM_SIGNAL_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - _mode, _shift); + _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_RateOfChange.mqh b/Indicators/Indi_RateOfChange.mqh index 438d4d6b3..076f4798a 100644 --- a/Indicators/Indi_RateOfChange.mqh +++ b/Indicators/Indi_RateOfChange.mqh @@ -110,16 +110,17 @@ class Indi_RateOfChange : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_RateOfChange::iROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, - _shift, THIS_PTR); + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_SAR.mqh b/Indicators/Indi_SAR.mqh index 570232fa0..2381c9cf3 100644 --- a/Indicators/Indi_SAR.mqh +++ b/Indicators/Indi_SAR.mqh @@ -102,16 +102,17 @@ class Indi_SAR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _shift, THIS_PTR); + _value = Indi_SAR::iSAR(GetSymbol(), GetTf(), GetStep(), GetMax(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetStep(), - GetMax() /*]*/, _mode, _shift); + GetMax() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_StdDev.mqh b/Indicators/Indi_StdDev.mqh index 097771e74..4ef932b03 100644 --- a/Indicators/Indi_StdDev.mqh +++ b/Indicators/Indi_StdDev.mqh @@ -226,22 +226,23 @@ class Indi_StdDev : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_StdDev::iStdDev(GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), GetMAMethod(), - GetAppliedPrice(), _shift, THIS_PTR); + GetAppliedPrice(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, Get(CHART_PARAM_SYMBOL), Get(CHART_PARAM_TF), iparams.GetCustomIndicatorName(), /*[*/ GetMAPeriod(), GetMAShift(), GetMAMethod() /*]*/, 0, - _shift); + _ishift); break; case IDATA_INDICATOR: _value = Indi_StdDev::iStdDevOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetMAPeriod(), GetMAShift(), - GetAppliedPrice(), _shift, THIS_PTR); + GetAppliedPrice(), _ishift, THIS_PTR); break; } return _value; diff --git a/Indicators/Indi_Stochastic.mqh b/Indicators/Indi_Stochastic.mqh index 60628f69f..d60246205 100644 --- a/Indicators/Indi_Stochastic.mqh +++ b/Indicators/Indi_Stochastic.mqh @@ -119,17 +119,18 @@ class Indi_Stochastic : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = LINE_MAIN, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = LINE_MAIN, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_Stochastic::iStochastic(GetSymbol(), GetTf(), GetKPeriod(), GetDPeriod(), GetSlowing(), - GetMAMethod(), GetPriceField(), _mode, _shift, THIS_PTR); + GetMAMethod(), GetPriceField(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetKPeriod(), - GetDPeriod(), GetSlowing() /*]*/, _mode, _shift); + GetDPeriod(), GetSlowing() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_TEMA.mqh b/Indicators/Indi_TEMA.mqh index 9b1d201d4..3cc9e949b 100644 --- a/Indicators/Indi_TEMA.mqh +++ b/Indicators/Indi_TEMA.mqh @@ -126,16 +126,17 @@ class Indi_TEMA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_TEMA::iTEMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetTEMAShift(), GetAppliedPrice() /*]*/, 0, - _shift, THIS_PTR); + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(), - GetTEMAShift() /*]*/, 0, _shift); + GetTEMAShift() /*]*/, 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_TRIX.mqh b/Indicators/Indi_TRIX.mqh index b30899b8b..a8086bd27 100644 --- a/Indicators/Indi_TRIX.mqh +++ b/Indicators/Indi_TRIX.mqh @@ -127,16 +127,17 @@ class Indi_TRIX : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = - Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR); + _value = Indi_TRIX::iTriX(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _ishift, + THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_UltimateOscillator.mqh b/Indicators/Indi_UltimateOscillator.mqh index 6a528dffa..7788bd77b 100644 --- a/Indicators/Indi_UltimateOscillator.mqh +++ b/Indicators/Indi_UltimateOscillator.mqh @@ -209,20 +209,21 @@ class Indi_UltimateOscillator : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_UltimateOscillator::iUO(GetSymbol(), GetTf(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, _mode, - _shift, THIS_PTR); + _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastPeriod(), GetMiddlePeriod(), GetSlowPeriod(), GetFastK(), GetMiddleK(), GetSlowK() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_VIDYA.mqh b/Indicators/Indi_VIDYA.mqh index 9e1d39bf0..a5647974c 100644 --- a/Indicators/Indi_VIDYA.mqh +++ b/Indicators/Indi_VIDYA.mqh @@ -147,19 +147,20 @@ class Indi_VIDYA : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_VIDYA::iVIDyA(GetSymbol(), GetTf(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift(), - GetAppliedPrice() /*]*/, 0, _shift, THIS_PTR); + GetAppliedPrice() /*]*/, 0, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetCMOPeriod(), GetMAPeriod(), GetVIDYAShift() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_VROC.mqh b/Indicators/Indi_VROC.mqh index 5ed32df45..2170fa831 100644 --- a/Indicators/Indi_VROC.mqh +++ b/Indicators/Indi_VROC.mqh @@ -130,16 +130,17 @@ class Indi_VROC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_VROC::iVROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift, + _value = Indi_VROC::iVROC(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _shift); + /*[*/ GetPeriod(), GetAppliedVolume() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_Volumes.mqh b/Indicators/Indi_Volumes.mqh index 29fea52dd..786f9fbbe 100644 --- a/Indicators/Indi_Volumes.mqh +++ b/Indicators/Indi_Volumes.mqh @@ -124,15 +124,16 @@ class Indi_Volumes : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_Volumes::iVolumes(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _shift, THIS_PTR); + _value = Indi_Volumes::iVolumes(GetSymbol(), GetTf(), /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetAppliedVolume() /*]*/, _mode, _shift); + /*[*/ GetAppliedVolume() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_WPR.mqh b/Indicators/Indi_WPR.mqh index 1aad02998..8dcc258aa 100644 --- a/Indicators/Indi_WPR.mqh +++ b/Indicators/Indi_WPR.mqh @@ -101,16 +101,17 @@ class Indi_WPR : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; - _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _shift, THIS_PTR); + _value = Indi_WPR::iWPR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, - 0, _shift); + 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_WilliamsAD.mqh b/Indicators/Indi_WilliamsAD.mqh index 03987b796..754cff808 100644 --- a/Indicators/Indi_WilliamsAD.mqh +++ b/Indicators/Indi_WilliamsAD.mqh @@ -124,14 +124,15 @@ class Indi_WilliamsAD : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: - _value = Indi_WilliamsAD::iWAD(GetSymbol(), GetTf(), _mode, _shift, THIS_PTR); + _value = Indi_WilliamsAD::iWAD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: - _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _shift); + _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), 0, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZag.mqh b/Indicators/Indi_ZigZag.mqh index 9c207f57e..94fa26e33 100644 --- a/Indicators/Indi_ZigZag.mqh +++ b/Indicators/Indi_ZigZag.mqh @@ -334,17 +334,18 @@ class Indi_ZigZag : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_ZigZag::iZigZag(GetSymbol(), GetTf(), GetDepth(), GetDeviation(), GetBackstep(), - (ENUM_ZIGZAG_LINE)_mode, _shift, THIS_PTR); + (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: istate.handle = istate.is_changed ? INVALID_HANDLE : istate.handle; _value = Indi_ZigZag::iCustomZigZag(GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), GetDepth(), - GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _shift, THIS_PTR); + GetDeviation(), GetBackstep(), (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); break; default: SetUserError(ERR_INVALID_PARAMETER); diff --git a/Indicators/Indi_ZigZagColor.mqh b/Indicators/Indi_ZigZagColor.mqh index 90c5ed66e..26489fd8f 100644 --- a/Indicators/Indi_ZigZagColor.mqh +++ b/Indicators/Indi_ZigZagColor.mqh @@ -268,23 +268,22 @@ class Indi_ZigZagColor : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { - ResetLastError(); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_BUILTIN: _value = Indi_ZigZagColor::iZigZagColor(GetSymbol(), GetTf(), GetDepth(), GetDeviation(), GetBackstep(), - (ENUM_ZIGZAG_LINE)_mode, _shift, THIS_PTR); + (ENUM_ZIGZAG_LINE)_mode, _ishift, THIS_PTR); break; case IDATA_ICUSTOM: _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), - /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _shift); + /*[*/ GetDepth(), GetDeviation(), GetBackstep() /*]*/, _mode, _ishift); break; default: SetUserError(ERR_INVALID_PARAMETER); + break; } - istate.is_ready = _LastError == ERR_NO_ERROR; - istate.is_changed = false; return _value; } diff --git a/Indicators/OHLC/Indi_OHLC.mqh b/Indicators/OHLC/Indi_OHLC.mqh index cc1b5f926..7d7d26d93 100644 --- a/Indicators/OHLC/Indi_OHLC.mqh +++ b/Indicators/OHLC/Indi_OHLC.mqh @@ -60,7 +60,8 @@ class Indi_OHLC : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); ENUM_APPLIED_PRICE _ap = PRICE_OPEN; switch (_mode) { case INDI_OHLC_CLOSE: @@ -76,7 +77,7 @@ class Indi_OHLC : public Indicator { _ap = PRICE_LOW; break; } - return ChartStatic::iPrice(_ap, GetSymbol(), GetTf(), _shift); + return ChartStatic::iPrice(_ap, GetSymbol(), GetTf(), _ishift); } /** diff --git a/Indicators/Price/Indi_Price.mqh b/Indicators/Price/Indi_Price.mqh index 4f155f775..74cd43db8 100644 --- a/Indicators/Price/Indi_Price.mqh +++ b/Indicators/Price/Indi_Price.mqh @@ -62,8 +62,9 @@ class Indi_Price : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { - return ChartStatic::iPrice(iparams.GetAppliedPrice(), GetSymbol(), GetTf(), _shift); + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); + return ChartStatic::iPrice(iparams.GetAppliedPrice(), GetSymbol(), GetTf(), _ishift); } /** diff --git a/Indicators/Special/Indi_Math.mqh b/Indicators/Special/Indi_Math.mqh index dd11760b7..033377c04 100644 --- a/Indicators/Special/Indi_Math.mqh +++ b/Indicators/Special/Indi_Math.mqh @@ -93,8 +93,9 @@ class Indi_Math : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { double _value = EMPTY_VALUE; + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); switch (iparams.idstype) { case IDATA_INDICATOR: if (!indi_src.IsSet()) { @@ -112,12 +113,12 @@ class Indi_Math : public Indicator { case MATH_OP_MODE_BUILTIN: _value = Indi_Math::iMathOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetOpBuiltIn(), GetMode1(), GetMode2(), GetShift1(), - GetShift2() /*]*/, 0, _shift, &this); + GetShift2() /*]*/, 0, _ishift, &this); break; case MATH_OP_MODE_CUSTOM_FUNCTION: _value = Indi_Math::iMathOnIndicator(GetDataSource(), GetSymbol(), GetTf(), /*[*/ GetOpFunction(), GetMode1(), GetMode2(), GetShift1(), - GetShift2() /*]*/, 0, _shift, &this); + GetShift2() /*]*/, 0, _ishift, &this); break; } break; diff --git a/Indicators/Tick/Indi_TickMt.mqh b/Indicators/Tick/Indi_TickMt.mqh index af93a1ed6..fd83cfdc7 100644 --- a/Indicators/Tick/Indi_TickMt.mqh +++ b/Indicators/Tick/Indi_TickMt.mqh @@ -56,7 +56,8 @@ class Indi_TickMt : public Indicator { /** * Returns the indicator's value. */ - virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) { + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { + int _ishift = _shift >= 0 ? _shift : iparams.GetShift(); MqlTick _tick = SymbolInfoStatic::GetTick(_Symbol); switch (_mode) { case 0: diff --git a/tests/DrawIndicatorTest.mq5 b/tests/DrawIndicatorTest.mq5 index 19786332b..0ec2fc83b 100644 --- a/tests/DrawIndicatorTest.mq5 +++ b/tests/DrawIndicatorTest.mq5 @@ -151,14 +151,9 @@ bool InitIndicators() { * Print indicators. */ bool PrintIndicators(string _prefix = "") { + ResetLastError(); for (DictIterator iter = indis.Begin(); iter.IsValid(); ++iter) { IndicatorBase *_indi = iter.Value(); - MqlParam _value = _indi.GetEntryValue(); - if (GetLastError() == ERR_INDICATOR_DATA_NOT_FOUND || - GetLastError() == ERR_USER_ERROR_FIRST + ERR_USER_INVALID_BUFF_NUM) { - ResetLastError(); - continue; - } if (_indi.Get(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_READY))) { PrintFormat("%s: %s: %s", _prefix, _indi.GetName(), _indi.ToString()); } diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index c112c61d5..60a416e0c 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -557,7 +557,7 @@ bool PrintIndicators(string _prefix = "") { } string _indi_name = _indi.GetFullName(); - MqlParam _value = _indi.GetEntryValue(); + IndicatorDataEntryValue _value = _indi.GetEntryValue(); if (GetLastError() == ERR_INDICATOR_DATA_NOT_FOUND || GetLastError() == ERR_USER_ERROR_FIRST + ERR_USER_INVALID_BUFF_NUM) { ResetLastError(); From 38586ef9b1f46b580c52008fec1f21153eb34736 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Nov 2021 21:18:25 +0000 Subject: [PATCH 59/97] Indicator: Removes redundant methods --- Indicator.mqh | 54 --------------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/Indicator.mqh b/Indicator.mqh index b2e6171b7..52aec6977 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -994,60 +994,6 @@ class Indicator : public IndicatorBase { _entry.AddFlags(_entry.GetDataTypeFlags(iparams.GetDataValueType())); }; - /** - * Returns the indicator's entry value for the given shift and mode. - * - * @see: DataParamEntry. - * - * @return - * Returns DataParamEntry struct filled with a single value. - */ - /* - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) { - IndicatorDataEntry _entry = GetEntry(fmax(_shift, _shift >= 0 ? _shift : iparams.GetShift())); - DataParamEntry _value_entry; - switch (iparams.GetDataValueType()) { - case TYPE_BOOL: - case TYPE_CHAR: - case TYPE_INT: - _value_entry = _entry.GetValue(_mode); - break; - case TYPE_LONG: - _value_entry = _entry.GetValue(_mode); - break; - case TYPE_UINT: - _value_entry = _entry.GetValue(_mode); - break; - case TYPE_ULONG: - _value_entry = _entry.GetValue(_mode); - break; - case TYPE_DOUBLE: - _value_entry = _entry.GetValue(_mode); - break; - case TYPE_FLOAT: - _value_entry = _entry.GetValue(_mode); - break; - case TYPE_STRING: - case TYPE_UCHAR: - default: - SetUserError(ERR_INVALID_PARAMETER); - break; - } - return _value_entry; - } - */ - - /** - * Returns the indicator's value. - */ - /* - virtual double GetValue(int _shift = -1, int _mode = 0) { - _shift = _shift >= 0 ? _shift : iparams.GetShift(); - istate.is_changed = false; - istate.is_ready = false; - return EMPTY_VALUE; - } - */ }; #endif From 1f2902c828f0b854b3d64f3d228451386d08f53f Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 8 Nov 2021 23:36:04 +0000 Subject: [PATCH 60/97] GHA: Adds Tick tests --- .github/workflows/test-tick.yml | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/test-tick.yml diff --git a/.github/workflows/test-tick.yml b/.github/workflows/test-tick.yml new file mode 100644 index 000000000..941fe371a --- /dev/null +++ b/.github/workflows/test-tick.yml @@ -0,0 +1,58 @@ +--- +name: Test Tick + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - 'Tick/**.h' + - '.github/workflows/test-tick.yml' + push: + paths: + - 'Tick/**.h' + - '.github/workflows/test-tick.yml' + +jobs: + + Compile: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Compile + uses: fx31337/mql-compile-action@master + with: + path: 'Tick/tests' + verbose: true + - name: Print compiled files + run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' + shell: powershell + - name: Upload artifacts (MQL4) + uses: actions/upload-artifact@v2 + with: + name: files-ex4 + path: '**/*.ex4' + - name: Upload artifacts (MQL5) + uses: actions/upload-artifact@v2 + with: + name: files-ex5 + path: '**/*.ex5' + + Tick-Tests-MQL4: + defaults: + run: + shell: bash + working-directory: Tick/tests + needs: Compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - TickManager.test + steps: + - uses: actions/download-artifact@v2 + with: + name: files-ex4 + - name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Script: ${{ matrix.test }} From 3b2045d447ef177ad10e059b1719991a78cd5748 Mon Sep 17 00:00:00 2001 From: kenorb Date: Thu, 28 Oct 2021 21:58:12 +0100 Subject: [PATCH 61/97] Chart: ChartTf: Adds SecsToTf() --- Chart.struct.tf.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/Chart.struct.tf.h b/Chart.struct.tf.h index 6c91b1c16..49c7c88f3 100644 --- a/Chart.struct.tf.h +++ b/Chart.struct.tf.h @@ -116,6 +116,69 @@ struct ChartTf { /* Static methods */ + /** + * Converts number of seconds per bar to chart's timeframe. + * + * @param _secs + * Number of seconds per one bar chart (OHLC). + * + * @return ENUM_TIMEFRAMES + * Returns enum representing chart's timeframe value. + */ + static ENUM_TIMEFRAMES SecsToTf(uint _secs = 0) { + switch (_secs) { + case 0: + return PERIOD_CURRENT; + case 60: + return PERIOD_M1; // 1 minute. + case 60 * 2: + return PERIOD_M2; // 2 minutes (non-standard). + case 60 * 3: + return PERIOD_M3; // 3 minutes (non-standard). + case 60 * 4: + return PERIOD_M4; // 4 minutes (non-standard). + case 60 * 5: + return PERIOD_M5; // 5 minutes. + case 60 * 6: + return PERIOD_M6; // 6 minutes (non-standard). + case 60 * 10: + return PERIOD_M10; // 10 minutes (non-standard). + case 60 * 12: + return PERIOD_M12; // 12 minutes (non-standard). + case 60 * 15: + return PERIOD_M15; // 15 minutes. + case 60 * 20: + return PERIOD_M20; // 20 minutes (non-standard). + case 60 * 30: + return PERIOD_M30; // 30 minutes. + case 60 * 60: + return PERIOD_H1; // 1 hour. + case 60 * 60 * 2: + return PERIOD_H2; // 2 hours (non-standard). + case 60 * 60 * 3: + return PERIOD_H3; // 3 hours (non-standard). + case 60 * 60 * 4: + return PERIOD_H4; // 4 hours. + case 60 * 60 * 6: + return PERIOD_H6; // 6 hours (non-standard). + case 60 * 60 * 8: + return PERIOD_H8; // 8 hours (non-standard). + case 60 * 60 * 12: + return PERIOD_H12; // 12 hours (non-standard). + case 60 * 60 * 24: + return PERIOD_D1; // Daily. + case 60 * 60 * 24 * 7: + return PERIOD_W1; // Weekly. + default: + break; + } + if (_secs >= 60 * 60 * 24 * 28 && _secs <= 60 * 60 * 24 * 31) { + return PERIOD_MN1; // Monthly range. + } + SetUserError(ERR_INVALID_PARAMETER); + return PERIOD_CURRENT; + } + /** * Convert period to proper chart timeframe value. * From 182f79f3ef8eb2b7faadd3bebc5f3e0e322b9187 Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 9 Nov 2021 13:09:14 +0000 Subject: [PATCH 62/97] Indi_AC: Sets 2 modes when using iCustom() --- Indicators/Indi_AC.mqh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Indicators/Indi_AC.mqh b/Indicators/Indi_AC.mqh index be9fe709b..b6e10fca1 100644 --- a/Indicators/Indi_AC.mqh +++ b/Indicators/Indi_AC.mqh @@ -39,6 +39,11 @@ struct IndiACParams : IndicatorParams { SetDataValueRange(IDATA_RANGE_MIXED); SetCustomIndicatorName("Examples\\Accelerator"); shift = _shift; + switch (idstype) { + case IDATA_ICUSTOM: + SetMaxModes(2); + break; + } }; IndiACParams(IndiACParams &_params, ENUM_TIMEFRAMES _tf) { THIS_REF = _params; From f60a9fc50d5095b2d04979b4982cc9528d734fdc Mon Sep 17 00:00:00 2001 From: kenorb Date: Tue, 9 Nov 2021 15:04:31 +0000 Subject: [PATCH 63/97] Indicator: Moves Init() to protected section --- Indicator.mqh | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Indicator.mqh b/Indicator.mqh index 52aec6977..b04a0bb63 100644 --- a/Indicator.mqh +++ b/Indicator.mqh @@ -59,6 +59,29 @@ class Indicator : public IndicatorBase { // Structs. TS iparams; + protected: + /* Protected methods */ + + /** + * It's called on class initialization. + */ + bool Init() { + ArrayResize(value_storages, iparams.GetMaxModes()); + switch (iparams.GetDataSourceType()) { + case IDATA_BUILTIN: + break; + case IDATA_ICUSTOM: + break; + case IDATA_INDICATOR: + if (!indi_src.IsSet()) { + // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); + // SetDataSource(_indi_price, true, PRICE_OPEN); + } + break; + } + return InitDraw(); + } + public: /* Indicator enumerations */ @@ -104,28 +127,6 @@ class Indicator : public IndicatorBase { */ ~Indicator() { DeinitDraw(); } - /* Init methods */ - - /** - * It's called on class initialization. - */ - bool Init() { - ArrayResize(value_storages, iparams.GetMaxModes()); - switch (iparams.GetDataSourceType()) { - case IDATA_BUILTIN: - break; - case IDATA_ICUSTOM: - break; - case IDATA_INDICATOR: - if (!indi_src.IsSet()) { - // Indi_Price* _indi_price = Indi_Price::GetCached(GetSymbol(), GetTf(), iparams.GetShift()); - // SetDataSource(_indi_price, true, PRICE_OPEN); - } - break; - } - return InitDraw(); - } - /** * Initialize indicator data drawing on custom data. */ @@ -993,7 +994,6 @@ class Indicator : public IndicatorBase { virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) { _entry.AddFlags(_entry.GetDataTypeFlags(iparams.GetDataValueType())); }; - }; #endif From c508d52a2a1e0d03a3b2d24a38a5b7620069f02e Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Fri, 12 Nov 2021 16:55:17 +0100 Subject: [PATCH 64/97] Fixes problem with non-visual mode 4086 errors due to BarsCalculated() returning an error even if iCustom was not yet executed. --- Indicator.define.h | 14 ++++++++------ IndicatorBase.h | 11 +++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Indicator.define.h b/Indicator.define.h index 6743cba67..d5056e91f 100644 --- a/Indicator.define.h +++ b/Indicator.define.h @@ -43,12 +43,14 @@ } \ SET_HANDLE; \ } \ - int _bars_calc = ::BarsCalculated(_handle); \ - if (GetLastError() > 0) { \ - return EMPTY_VALUE; \ - } else if (_bars_calc <= 2) { \ - SetUserError(ERR_USER_INVALID_BUFF_NUM); \ - return EMPTY_VALUE; \ + if (Terminal::IsVisualMode()) { \ + int _bars_calc = BarsCalculated(_handle); \ + if (GetLastError() > 0) { \ + return EMPTY_VALUE; \ + } else if (_bars_calc <= 2) { \ + SetUserError(ERR_USER_INVALID_BUFF_NUM); \ + return EMPTY_VALUE; \ + } \ } \ if (::CopyBuffer(_handle, _mode, _shift, 1, _res) < 0) { \ return ArraySize(_res) > 0 ? _res[0] : EMPTY_VALUE; \ diff --git a/IndicatorBase.h b/IndicatorBase.h index 69081ff71..abbde201c 100644 --- a/IndicatorBase.h +++ b/IndicatorBase.h @@ -79,6 +79,17 @@ double iCustom5(string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C ICUSTOM_DEF(_handlers.Set(_key, _handle), COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h COMMA _i COMMA _j); } +template +double iCustom5(string _symbol, ENUM_TIMEFRAMES _tf, string _name, A _a, B _b, C _c, D _d, E _e, F _f, G _g, H _h, I _i, + J _j, K _k, L _l, M _m, int _mode, int _shift) { + ResetLastError(); + static Dict _handlers; + string _key = Util::MakeKey(_symbol, (string)_tf, _name, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j); + int _handle = _handlers.GetByKey(_key); + ICUSTOM_DEF(_handlers.Set(_key, _handle), COMMA _a COMMA _b COMMA _c COMMA _d COMMA _e COMMA _f COMMA _g COMMA _h + COMMA _i COMMA _j COMMA _k COMMA _l COMMA _m); +} #endif /** From b85e81526840c42feca777a1c07b24f1653388c9 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 5 Dec 2021 15:57:41 +0000 Subject: [PATCH 65/97] GHA: Uses 4.0.0.1349 to run main tests --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e9f32e28..38c04ce85 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -89,6 +89,7 @@ jobs: BtDays: 1-8 BtMonths: 1 BtYears: 2020 + MtVersion: 4.0.0.1349 TestExpert: ${{ matrix.test }} timeout-minutes: 10 From fee70852c5d0003204794bbc8952725e9b0ec406 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 5 Dec 2021 16:17:47 +0000 Subject: [PATCH 66/97] GHA: Uses 4.0.0.1349 to compile main tests --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 38c04ce85..f1062a969 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,7 @@ jobs: uses: fx31337/mql-compile-action@master with: init-platform: true + mt-version: 4.0.0.1349 verbose: true - name: Print compiled files run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname' From 43829c31457811b856de8f391c2738bd278f6080 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 5 Dec 2021 23:17:13 +0000 Subject: [PATCH 67/97] GHA: Removes init-platform due to hang --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f1062a969..9e28bced3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,6 @@ jobs: - name: Compile uses: fx31337/mql-compile-action@master with: - init-platform: true mt-version: 4.0.0.1349 verbose: true - name: Print compiled files From 1aa8db9bb1bc3c1e992a080ab258106ed8ea40e0 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Mon, 8 Nov 2021 15:30:26 +0100 Subject: [PATCH 68/97] Fixed Dicts to take into consideration overflow listeners. --- Dict.mqh | 22 ++++++++++++++-------- DictBase.mqh | 17 +++++++++++++++++ DictObject.mqh | 22 ++++++++++++++-------- DictStruct.mqh | 21 ++++++++++++++------- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Dict.mqh b/Dict.mqh index 3fe692a31..cd55d66ba 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -205,24 +205,30 @@ class Dict : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { - // Will resize dict if there were performance problems before. - if (allow_resize && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; - } - } - if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); - DebugBreak(); return false; } unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + if (keySlot == NULL && !IsGrowUpAllowed()) { + // Resize is prohibited. + return false; + } + + // Will resize dict if there were performance problems before. + if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); + } + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (overflow_listener != NULL) { diff --git a/DictBase.mqh b/DictBase.mqh index 534f91e8a..daeaaae7a 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -257,6 +257,18 @@ class DictBase { // No key found. } + /** + * Checks whether overflow listener allows dict to grow up. + */ + bool IsGrowUpAllowed() { + if (overflow_listener == NULL) { + return true; + } + + // Checking if overflow listener allows resize from current to higher number of slots. + return overflow_listener(DICT_OVERFLOW_REASON_FULL, Size(), 0); + } + /** * Moves last slot to given one to fill the hole after removing the value. */ @@ -280,6 +292,11 @@ class DictBase { */ const unsigned int Size() { return _DictSlots_ref._num_used; } + /** + * Returns number of all (reserved) DictSlots. + */ + const unsigned int ReservedSize() { return ArraySize(_DictSlots_ref.DictSlots); } + /** * Checks whether given key exists in the dictionary. */ diff --git a/DictObject.mqh b/DictObject.mqh index 4491707cb..8bcc9d412 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -192,24 +192,30 @@ class DictObject : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - // Will resize dict if there were performance problems before. - if (allow_resize && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; - } - } - if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { Alert("Warning: Dict already operates as a list, not a dictionary!"); - DebugBreak(); return false; } unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + if (keySlot == NULL && !IsGrowUpAllowed()) { + // Resize is prohibited. + return false; + } + + // Will resize dict if there were performance problems before. + if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); + } + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (overflow_listener != NULL) { diff --git a/DictStruct.mqh b/DictStruct.mqh index b6ea1eac4..b4cb0d747 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -252,13 +252,6 @@ class DictStruct : public DictBase { * Inserts value into given array of DictSlots. */ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { - // Will resize dict if there were performance problems before. - if (allow_resize && !dictSlotsRef.IsPerformant()) { - if (!GrowUp()) { - return false; - } - } - if (_mode == DictModeUnknown) _mode = DictModeDict; else if (_mode != DictModeDict) { @@ -269,6 +262,20 @@ class DictStruct : public DictBase { unsigned int position; DictSlot* keySlot = GetSlotByKey(dictSlotsRef, key, position); + if (keySlot == NULL && !IsGrowUpAllowed()) { + // Resize is prohibited. + return false; + } + + // Will resize dict if there were performance problems before. + if (allow_resize && IsGrowUpAllowed() && !dictSlotsRef.IsPerformant()) { + if (!GrowUp()) { + return false; + } + // We now have new positions of slots, so we have to take the corrent slot again. + keySlot = GetSlotByKey(dictSlotsRef, key, position); + } + if (keySlot == NULL && dictSlotsRef._num_used == ArraySize(dictSlotsRef.DictSlots)) { // No DictSlotsRef.DictSlots available. if (overflow_listener != NULL) { From 25945cc55c5238e15740841538589d07238206cc Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 8 Jan 2022 23:25:02 +0000 Subject: [PATCH 69/97] Improves tasks return logic --- EA.mqh | 6 ++++-- Strategy.mqh | 9 +++++---- Trade.mqh | 43 +++++++++++++++++++++---------------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/EA.mqh b/EA.mqh index a8525712d..033820ac7 100644 --- a/EA.mqh +++ b/EA.mqh @@ -882,6 +882,7 @@ class EA { * Returns true when the condition is met. */ bool CheckCondition(ENUM_EA_CONDITION _cond, DataParamEntry &_args[]) { + bool _result = false; switch (_cond) { case EA_COND_IS_ACTIVE: return estate.IsActive(); @@ -908,8 +909,9 @@ class EA { return estate.IsOnQuit(); default: logger.Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; + break; } + return _result; } bool CheckCondition(ENUM_EA_CONDITION _cond) { ARRAY(DataParamEntry, _args); @@ -925,7 +927,7 @@ class EA { * Returns true when the action has been executed successfully. */ bool ExecuteAction(ENUM_EA_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; long arg_size = ArraySize(_args); switch (_action) { case EA_ACTION_DISABLE: diff --git a/Strategy.mqh b/Strategy.mqh index c8bed49a1..38b412f66 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -684,7 +684,7 @@ class Strategy : public Object { * Returns true when the condition is met. */ bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; long arg_size = ArraySize(_args); long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; @@ -718,8 +718,9 @@ class Strategy : public Object { return _result; default: GetLogger().Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; + break; } + return _result; } bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, long _arg1) { ARRAY(DataParamEntry, _args); @@ -751,7 +752,7 @@ class Strategy : public Object { * Returns true when the action has been executed successfully. */ bool ExecuteAction(ENUM_STRATEGY_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; double arg1d = EMPTY_VALUE; double arg2d = EMPTY_VALUE; double arg3d = EMPTY_VALUE; @@ -813,7 +814,7 @@ class Strategy : public Object { return true; default: GetLogger().Error(StringFormat("Invalid Strategy action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - return false; + break; } return _result; } diff --git a/Trade.mqh b/Trade.mqh index bc01e1f56..1d5a2a64e 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -1729,7 +1729,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Returns true when the condition is met. */ bool CheckCondition(ENUM_TRADE_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; Ref _oquery_ref; @@ -1798,7 +1798,6 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: logger.Error(StringFormat("Invalid trade condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - _result = false; break; } return _result; @@ -1827,7 +1826,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. * Returns true when the condition is met. */ bool ExecuteAction(ENUM_TRADE_ACTION _action, DataParamEntry &_args[]) { - bool _result = true; + bool _result = false; Ref _oquery_ref; if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _oquery_ref = OrderQuery::GetInstance(orders_active); @@ -1852,21 +1851,21 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDER_CLOSE_MOST_LOSS: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result &= _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref.Ptr() + .FindByPropViaOp(ORDER_PROP_PROFIT, + STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_LT)) + .Ptr() + .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; case TRADE_ACTION_ORDER_CLOSE_MOST_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE) && orders_active.Size() > 0) { - _result &= _oquery_ref.Ptr() - .FindByPropViaOp(ORDER_PROP_PROFIT, - STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) - .Ptr() - .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); + _result = _oquery_ref.Ptr() + .FindByPropViaOp(ORDER_PROP_PROFIT, + STRUCT_ENUM(OrderQuery, ORDER_QUERY_OP_GT)) + .Ptr() + .OrderClose(ORDER_REASON_CLOSED_BY_ACTION); RefreshActiveOrders(true, true); } break; @@ -1874,33 +1873,33 @@ HistorySelect(0, TimeCurrent()); // Select history for access. return RequestSend(GetTradeOpenRequest((ENUM_ORDER_TYPE)_args[0].integer_value)); case TRADE_ACTION_ORDERS_CLOSE_ALL: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseAll(ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseAll(ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_IN_PROFIT: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaProp( - ORDER_PROP_PROFIT_PIPS, (int)chart.Ptr().GetSpreadInPips(), MATH_COND_GT, - ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaProp( + ORDER_PROP_PROFIT_PIPS, (int)chart.Ptr().GetSpreadInPips(), MATH_COND_GT, + ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_IN_TREND: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaCmd(GetTrendOp(0), ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(GetTrendOp(0), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_IN_TREND_NOT: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaCmd(Order::NegateOrderType(GetTrendOp(0)), ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(Order::NegateOrderType(GetTrendOp(0)), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; case TRADE_ACTION_ORDERS_CLOSE_BY_TYPE: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result &= OrdersCloseViaCmd((ENUM_ORDER_TYPE)_args[0].integer_value, ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd((ENUM_ORDER_TYPE)_args[0].integer_value, ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; @@ -1911,7 +1910,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _oquery_ref.Ptr() .FindPropBySum( _order_types1, ORDER_PROP_PROFIT, ORDER_TYPE); - _result &= + _result = OrdersCloseViaCmd(Order::NegateOrderType(_order_type_profitable), ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; @@ -1922,7 +1921,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. _oquery_ref.Ptr() .FindPropBySum( _order_types2, ORDER_PROP_PROFIT, ORDER_TYPE); - _result &= OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(_order_type_profitable2, ORDER_REASON_CLOSED_BY_ACTION) >= 0; } break; case TRADE_ACTION_ORDERS_LIMIT_SET: From 63cb49f6de42e6aa1196912a73140a8873a55daf Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:15:49 +0000 Subject: [PATCH 70/97] Task: TaskEntry: Uses int for getters --- Task/Task.struct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 5d8061c62..787e763cc 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -77,8 +77,8 @@ struct TaskEntry { // bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } bool IsValid() { return action.IsValid() && cond.IsValid(); } // Getters. - long GetActionId() { return action.GetId(); } - long GetConditionId() { return cond.GetId(); } + int GetActionId() { return action.GetId(); } + int GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } }; From 8c21c329d68c77cac3164404300cf06fa3ea3939 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:16:23 +0000 Subject: [PATCH 71/97] EA: Inherits from Taskable --- EA.mqh | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/EA.mqh b/EA.mqh index 033820ac7..841e822cb 100644 --- a/EA.mqh +++ b/EA.mqh @@ -52,7 +52,7 @@ #include "Trade/TradeSignal.h" #include "Trade/TradeSignalManager.h" -class EA { +class EA : public Taskable { protected: // Class variables. Account *account; @@ -663,9 +663,9 @@ class EA { */ bool TaskAdd(TaskEntry &_entry) { bool _result = false; - /* @fixme if (_entry.IsValid()) { - switch (_entry.GetConditionType()) { + /* @fixme + switch (_entry.GetConditionId()) { case COND_TYPE_ACCOUNT: _entry.SetConditionObject(account); break; @@ -676,7 +676,7 @@ class EA { _entry.SetConditionObject(trade.GetByKey(_Symbol)); break; } - switch (_entry.GetActionType()) { + switch (_entry.GetActionId()) { case ACTION_TYPE_EA: _entry.SetActionObject(THIS_PTR); break; @@ -684,9 +684,9 @@ class EA { _entry.SetActionObject(trade.GetByKey(_Symbol)); break; } + */ _result |= tasks.Push(_entry); } - */ return _result; } @@ -981,6 +981,57 @@ class EA { return EA::ExecuteAction(_action, _args); } + /* Tasks */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + // _entry_value.GetValue() + default: + break; + } + return _result; + } + /* Getters */ /** From 691b5a8bdae058dd72aa4e49639f5eb4e3d13e64 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:34:23 +0000 Subject: [PATCH 72/97] Taskable: Inherits from Object --- Task/Taskable.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Task/Taskable.h b/Task/Taskable.h index fe610aa77..f6adcae25 100644 --- a/Task/Taskable.h +++ b/Task/Taskable.h @@ -35,6 +35,7 @@ #define TASKABLE_H // Includes. +#include "../Object.mqh" #include "TaskAction.h" #include "TaskCondition.h" #include "TaskGetter.h" @@ -44,14 +45,14 @@ * Taskable class. */ template -class Taskable { +class Taskable : public Object { public: /* Special methods */ /** - * Class constructor. + * Class constructor with default arguments. */ - Taskable() {} + Taskable() : Object(GetPointer(this), __LINE__) {} /* Virtual methods */ From 9fdb894ca4ed56b857bf95e6a3189e13ca1e031c Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 15 Jan 2022 23:34:37 +0000 Subject: [PATCH 73/97] Strategy: Inherits from Taskable --- EA.mqh | 3 +-- Strategy.mqh | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/EA.mqh b/EA.mqh index 841e822cb..40e5b1610 100644 --- a/EA.mqh +++ b/EA.mqh @@ -45,8 +45,7 @@ #include "Strategy.mqh" #include "SummaryReport.mqh" #include "Task/Task.h" -#include "Task/TaskAction.enum.h" -#include "Task/TaskCondition.enum.h" +#include "Task/Taskable.h" #include "Terminal.mqh" #include "Trade.mqh" #include "Trade/TradeSignal.h" diff --git a/Strategy.mqh b/Strategy.mqh index 38b412f66..15ec64f03 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -37,6 +37,7 @@ class Trade; #include "Strategy.struct.h" #include "String.mqh" #include "Task/Task.h" +#include "Task/Taskable.h" #include "Trade.mqh" // Defines. @@ -85,7 +86,7 @@ class Trade; /** * Implements strategy class. */ -class Strategy : public Object { +class Strategy : public Taskable { public: StgParams sparams; @@ -122,7 +123,7 @@ class Strategy : public Object { * Class constructor. */ Strategy(StgParams &_sparams, TradeParams &_tparams, ChartParams &_cparams, string _name = "") - : sparams(_sparams), trade(_tparams, _cparams), Object(GetPointer(this), __LINE__) { + : sparams(_sparams), trade(_tparams, _cparams) { // Initialize variables. name = _name; MqlTick _tick = {0}; @@ -1254,6 +1255,57 @@ class Strategy : public Object { return _result; }; + /* Tasks */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + // _entry_value.GetValue() + default: + break; + } + return _result; + } + /* Serializers */ /** From a223bc39dc03dff9fad5b63a1dccb43bcf69cdb2 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 16:06:13 +0000 Subject: [PATCH 74/97] IndicatorsTest: Fixes Indi_Drawer --- tests/IndicatorsTest.mq5 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/IndicatorsTest.mq5 b/tests/IndicatorsTest.mq5 index 5d44e708b..880056e03 100644 --- a/tests/IndicatorsTest.mq5 +++ b/tests/IndicatorsTest.mq5 @@ -390,12 +390,12 @@ bool InitIndicators() { indi_rsi_on_price.Ptr().SetDataSource(indi_price_4_rsi.Ptr()); indis.Push(indi_rsi_on_price.Ptr()); - // Drawer (socket-based) indicator. + // Drawer (socket-based) indicator over RSI over Price. IndiDrawerParams drawer_params(14, /*unused*/ PRICE_OPEN); - // drawer_params.SetIndicatorData(indi_price_4_rsi); - // drawer_params.SetIndicatorMode(INDI_PRICE_MODE_OPEN); drawer_params.SetDraw(clrBisque, 0); - indis.Push(_indi_drawer = new Indi_Drawer(drawer_params)); + Ref indi_drawer_on_rsi = new Indi_Drawer(drawer_params); + indi_drawer_on_rsi.Ptr().SetDataSource(indi_rsi_on_price.Ptr(), PRICE_OPEN); + indis.Push(indi_drawer_on_rsi.Ptr()); // Applied Price over OHCL indicator. IndiAppliedPriceParams applied_price_params(); From 86b9c39b2b200f67a5cab0c88d97827c7f972f92 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 19:26:43 +0000 Subject: [PATCH 75/97] Task/TaskAction: Adds GetArg() --- Task/TaskAction.struct.h | 1 + Task/TaskCondition.struct.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 7014144c6..ab7db5b16 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -119,6 +119,7 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } + DataParamEntry GetArg(int _index) { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index bbd1c557e..1485a49d7 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -109,6 +109,7 @@ struct TaskConditionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } + DataParamEntry GetArg(int _index) { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } From 4b9fe8055450da93deeec26e35195a9f07ff0104 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 19:47:16 +0000 Subject: [PATCH 76/97] Indi_Drawer: Do not enforce double --- Indicators/Indi_Drawer.mqh | 2 -- 1 file changed, 2 deletions(-) diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh index 896e0a830..b18eebf98 100644 --- a/Indicators/Indi_Drawer.mqh +++ b/Indicators/Indi_Drawer.mqh @@ -72,8 +72,6 @@ class Indi_Drawer : public Indicator { int num_args = ArraySize(_args), i; IndicatorDataEntry entry(num_args - 1); - // @fixit Not sure if we should enforce double. - entry.AddFlags(INDI_ENTRY_FLAG_IS_DOUBLE); if (_action == INDI_ACTION_SET_VALUE) { iparams.SetMaxModes(num_args - 1); From 0a022cfd2524150298542d531b4bd62c1d8cb6d1 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 19:26:58 +0000 Subject: [PATCH 77/97] Adds Taskable.car.test --- .github/workflows/test-task.yml | 3 +- Task/tests/TaskSetter.test.mq5 | 2 +- Task/tests/Taskable.car.test.mq4 | 28 +++++ Task/tests/Taskable.car.test.mq5 | 203 +++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 Task/tests/Taskable.car.test.mq4 create mode 100644 Task/tests/Taskable.car.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index e0b0458c6..3a4e6abe8 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -49,11 +49,12 @@ jobs: matrix: test: - Task.test - - Taskable.test - TaskAction.test - TaskCondition.test - TaskGetter.test - TaskSetter.test + - Taskable.car.test + - Taskable.test steps: - uses: actions/download-artifact@v2 with: diff --git a/Task/tests/TaskSetter.test.mq5 b/Task/tests/TaskSetter.test.mq5 index 6769309c7..50fb1688e 100644 --- a/Task/tests/TaskSetter.test.mq5 +++ b/Task/tests/TaskSetter.test.mq5 @@ -46,7 +46,7 @@ class TaskSetterTest01 : protected TaskSetterBase { TaskSetterTest01Data data; public: - TaskSetterTest01() : data(0) {}; + TaskSetterTest01() : data(0){}; int GetValue() const { return data.GetValue(); } bool Set(const TaskSetterEntry &_entry, const TaskSetterTest01Data &_entry_value) { data.SetValue(data.GetValue() + _entry_value.GetValue()); diff --git a/Task/tests/Taskable.car.test.mq4 b/Task/tests/Taskable.car.test.mq4 new file mode 100644 index 000000000..ad723ca6d --- /dev/null +++ b/Task/tests/Taskable.car.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Taskable class. + */ + +// Includes. +#include "Taskable.car.test.mq5" diff --git a/Task/tests/Taskable.car.test.mq5 b/Task/tests/Taskable.car.test.mq5 new file mode 100644 index 000000000..db002a564 --- /dev/null +++ b/Task/tests/Taskable.car.test.mq5 @@ -0,0 +1,203 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2021, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Task class. + */ + +// Forward declaration. +struct DataParamEntry; + +// Includes. +#include "../../Data.struct.h" +#include "../../Test.mqh" +#include "../Task.h" + +// Implements test classes. +class Car : public Taskable { + protected: + enum ENUM_CAR_ACTION { + CAR_ACTION_NONE = 0, + CAR_ACTION_CONTINUE, + CAR_ACTION_SPEED_DEC_BY, + CAR_ACTION_SPEED_INC_BY, + CAR_ACTION_SPEED_SET_BY, + CAR_ACTION_STOP, + }; + enum ENUM_CAR_COND { + CAR_COND_NONE = 0, + CAR_COND_NEEDS_SERVICE, + CAR_COND_IS_MOVING_BACKWARD, + CAR_COND_IS_MOVING_FORWARD, + CAR_COND_IS_SPEED_MAX, + CAR_COND_IS_STOPPED, + }; + enum ENUM_CAR_PROP { + CAR_PROP_NONE = 0, + CAR_PROP_MILEAGE_CURR, + CAR_PROP_MILEAGE_MAX, + CAR_PROP_SPEED, + }; + int mileage_curr, mileage_max, speed_curr, speed_max; + + public: + Car(int _speed_max = 100, int _mileage_max = 10000) : mileage_curr(0), speed_max(_speed_max) {} + + /* Tasks */ + + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + case CAR_COND_NEEDS_SERVICE: + _result = mileage_curr > mileage_max; + break; + case CAR_COND_IS_MOVING_BACKWARD: + _result = speed_curr < 0; + break; + case CAR_COND_IS_MOVING_FORWARD: + _result = speed_curr > 0; + break; + case CAR_COND_IS_SPEED_MAX: + _result = speed_curr >= speed_max; + break; + case CAR_COND_IS_STOPPED: + _result = speed_curr == 0; + break; + default: + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + case CAR_PROP_MILEAGE_CURR: + _result = mileage_curr; + break; + case CAR_PROP_MILEAGE_MAX: + _result = mileage_max; + break; + case CAR_PROP_SPEED: + _result = speed_curr; + break; + default: + break; + } + return _result; + } + template + DataParamEntry Get(E _id) { + TaskGetterEntry _entry(_id); + return Get(_entry); + }; + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = false; + switch (_entry.GetId()) { + case CAR_ACTION_CONTINUE: + mileage_curr += speed_curr; + break; + case CAR_ACTION_SPEED_DEC_BY: + // speed_curr -= _entry.GetArg(); // @fixme + break; + case CAR_ACTION_SPEED_INC_BY: + // speed_curr += _entry.GetArg(); // @fixme + break; + case CAR_ACTION_SPEED_SET_BY: + // speed_curr = _entry.GetArg(); // @fixme + break; + case CAR_ACTION_STOP: + speed_curr = 0; + break; + default: + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = true; + switch (_entry.GetId()) { + case CAR_PROP_MILEAGE_CURR: + // mileage_curr = _entry_value.ToValue(); // @fixme + break; + case CAR_PROP_MILEAGE_MAX: + // mileage_max = _entry_value.ToValue(); // @fixme + break; + case CAR_PROP_SPEED: + // speed_curr = _entry_value.ToValue(); // @fixme + break; + default: + _result = false; + break; + } + return _result; + } + template + DataParamEntry Set(E _id) { + TaskSetterEntry _entry(_id); + return Set(_entry); + }; +}; + +// Test if car can drive. +bool TestCarCanDrive() { + bool _result = true; + Car *_car = new Car(); + _result &= _car.Get(STRUCT_ENUM(Car, CAR_PROP_SPEED)).ToValue() == 0; + delete _car; + return _result; +} + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + // @todo + _result &= TestCarCanDrive(); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 03bda7295b465f5b9b7e22189dad9fe708b68d33 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 20:33:44 +0000 Subject: [PATCH 78/97] Task/Task: Adds missing virtual methods --- Task/Task.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Task/Task.h b/Task/Task.h index 5d0864b3b..60ce05399 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -116,6 +116,57 @@ class Task : protected Taskable { /* Task methods */ + /** + * Checks a condition. + */ + virtual bool Check(const TaskConditionEntry &_entry) { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + break; + } + return _result; + } + + /** + * Gets a copy of structure. + */ + virtual TaskEntry Get(const TaskGetterEntry &_entry) { + TaskEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } + + /** + * Runs an action. + */ + virtual bool Run(const TaskActionEntry &_entry) { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + break; + } + return _result; + } + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const TaskEntry &_entry_value) { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + break; + } + return _result; + } + /* State methods */ /** From e5323fb61e50018357697dd0c95e953d73680cbc Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 20:35:02 +0000 Subject: [PATCH 79/97] Task.test: Adds TestTask01() --- Task/tests/Task.test.mq5 | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/Task/tests/Task.test.mq5 b/Task/tests/Task.test.mq5 index 623bd8d9e..24191b6f3 100644 --- a/Task/tests/Task.test.mq5 +++ b/Task/tests/Task.test.mq5 @@ -31,12 +31,50 @@ struct DataParamEntry; #include "../../Test.mqh" #include "../Task.h" +// Define test classes. +class ConditionType1 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ConditionType2 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ActionType1 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class ActionType2 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class TaskType1 : public Taskable { + bool Check(const TaskConditionEntry &_entry) { return true; } + MqlParam Get(const TaskGetterEntry &_entry) { + MqlParam _result; + return _result; + } + bool Run(const TaskActionEntry &_entry) { return true; } + bool Set(const TaskSetterEntry &_entry, const MqlParam &_entry_value) { return true; } +}; + +// Test 1. +bool TestTask01() { + bool _result = true; + Task _task1; + TaskAction _taction1; + TaskAction _taction2; + TaskCondition _tcond1; + TaskCondition _tcond2; + return _result; +} + /** * Implements Init event handler. */ int OnInit() { bool _result = true; - // @todo + _result &= TestTask01(); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 4355fedf885d7addb53d13d95fb1169d1cb1793a Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 16 Jan 2022 21:05:37 +0000 Subject: [PATCH 80/97] Task: Adds TaskObject --- .github/workflows/test-task.yml | 1 + Task/TaskAction.h | 2 +- Task/TaskCondition.h | 2 +- Task/TaskObject.h | 75 +++++++++++++++++++++++++++ Task/tests/TaskObject.test.mq4 | 28 ++++++++++ Task/tests/TaskObject.test.mq5 | 92 +++++++++++++++++++++++++++++++++ 6 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 Task/TaskObject.h create mode 100644 Task/tests/TaskObject.test.mq4 create mode 100644 Task/tests/TaskObject.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 3a4e6abe8..52dd9346f 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -52,6 +52,7 @@ jobs: - TaskAction.test - TaskCondition.test - TaskGetter.test + - TaskObject.test - TaskSetter.test - Taskable.car.test - Taskable.test diff --git a/Task/TaskAction.h b/Task/TaskAction.h index db6c78745..4c647f98e 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -43,7 +43,7 @@ * TaskAction class. */ template -class TaskAction : protected TaskActionBase { +class TaskAction : public TaskActionBase { protected: // Protected class variables. TaskActionEntry entry; // Action entry. diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 21670e684..30214c373 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -43,7 +43,7 @@ * TaskCondition class. */ template -class TaskCondition : protected TaskConditionBase { +class TaskCondition : public TaskConditionBase { public: protected: // Protected class variables. diff --git a/Task/TaskObject.h b/Task/TaskObject.h new file mode 100644 index 000000000..38db316b9 --- /dev/null +++ b/Task/TaskObject.h @@ -0,0 +1,75 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides integration with tasks (manages conditions and actions). + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_OBJECT_H +#define TASK_OBJECT_H + +// Includes. +#include "Task.h" + +template +class TaskObject : protected Task { + protected: + TaskAction action; + TaskCondition condition; + + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskObject(TaskActionEntry &_aentry, TaskConditionEntry &_centry) : action(_aentry), condition(_centry) {} + + /** + * Class deconstructor. + */ + ~TaskObject() {} + + /* Main methods */ + + /** + * Process task entry. + * + * @return + * Returns true when tasks has been processed. + */ + static bool Process(TaskEntry &_entry) { + bool _result = false; + // @todo + return _result; + } + + /* Other methods */ +}; +#endif // TASK_OBJECT_H diff --git a/Task/tests/TaskObject.test.mq4 b/Task/tests/TaskObject.test.mq4 new file mode 100644 index 000000000..a6d856946 --- /dev/null +++ b/Task/tests/TaskObject.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskObject class. + */ + +// Includes. +#include "TaskObject.test.mq5" diff --git a/Task/tests/TaskObject.test.mq5 b/Task/tests/TaskObject.test.mq5 new file mode 100644 index 000000000..c47a394ae --- /dev/null +++ b/Task/tests/TaskObject.test.mq5 @@ -0,0 +1,92 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskObject class. + */ + +// Forward declaration. +struct DataParamEntry; + +// Includes. +#include "../../Test.mqh" +#include "../TaskObject.h" + +// Define test classes. +class ConditionType1 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ConditionType2 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ActionType1 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class ActionType2 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class TaskType1 : public Taskable { + bool Check(const TaskConditionEntry &_entry) { return true; } + MqlParam Get(const TaskGetterEntry &_entry) { + MqlParam _result; + return _result; + } + bool Run(const TaskActionEntry &_entry) { return true; } + bool Set(const TaskSetterEntry &_entry, const MqlParam &_entry_value) { return true; } +}; + +// Test 1. +bool TestTaskObject01() { + bool _result = true; + TaskActionEntry _aentry; + TaskConditionEntry _centry; + // TaskAction _taction1; + // TaskAction _taction2; + // TaskCondition _tcond1; + // TaskCondition _tcond2; + TaskObject _task1(_aentry, _centry); + return _result; +} + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + _result &= TestTaskObject01(); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 912e3ef0b2f88b6084a2cef3d7d8eef600a4b2f8 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 17 Jan 2022 21:20:09 +0000 Subject: [PATCH 81/97] Task: Improves processing methods --- Task/Task.h | 27 +++++++++++------------ Task/Task.struct.h | 54 +++++++++++++++++++++++++++++++++++++++++++--- Task/TaskObject.h | 47 ++++++++++++++++++++++++++++++++++------ 3 files changed, 105 insertions(+), 23 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 60ce05399..1f937672d 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -72,13 +72,15 @@ class Task : protected Taskable { */ void Add(TaskEntry &_entry) { tasks.Push(_entry); } + /* Virtual methods */ + /** * Process tasks. * * @return * Returns true when tasks has been processed. */ - bool Process() { + virtual bool Process() { bool _result = true; for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { TaskEntry _entry = iter.Value(); @@ -93,24 +95,21 @@ class Task : protected Taskable { * @return * Returns true when tasks has been processed. */ - static bool Process(TaskEntry &_entry) { + virtual bool Process(TaskEntry &_entry) { bool _result = false; - /* @fixme if (_entry.IsActive()) { - if (TaskCondition::Test(_entry.GetCondition())) { - TaskActionEntry _action = _entry.GetAction(); - TaskAction::Execute(_action); - if (_action.IsDone()) { - _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, _action.IsDone()); - _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, _action.IsFailed()); - _entry.SetFlag(TASK_ENTRY_FLAG_IS_INVALID, _action.IsInvalid()); - _entry.RemoveFlags(TASK_ENTRY_FLAG_IS_ACTIVE); - } + _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); + if (_entry.IsDone()) { + _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_INVALID, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID))); + _entry.RemoveFlags(TASK_ENTRY_FLAG_IS_ACTIVE); } - _entry.last_process = TimeCurrent(); _result = true; } - */ return _result; } diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 787e763cc..f9cbf9815 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -36,6 +36,15 @@ #include "TaskCondition.struct.h" struct TaskEntry { + public: + /* Enumerations */ + enum ENUM_TASK_ENTRY_PROP { + TASK_ENTRY_PROP_NONE = 0, // None + TASK_ENTRY_PROP_EXPIRES, // Expires + TASK_ENTRY_PROP_LAST_PROCESS, // Last process + TASK_ENTRY_PROP_LAST_SUCCESS, // Last success + }; + protected: TaskActionEntry action; // TaskAction of the task. TaskConditionEntry cond; // TaskCondition of the task. @@ -60,6 +69,45 @@ struct TaskEntry { void TaskEntry(AE _aid, CE _cid) : action(_aid), cond(_cid) { Init(); }; + // Getters. + template + T Get(ENUM_TASK_ENTRY_PROP _prop) { + switch (_prop) { + case TASK_ENTRY_PROP_EXPIRES: // Expires + return (T)expires; + case TASK_ENTRY_PROP_LAST_PROCESS: // Last process + return (T)last_process; + case TASK_ENTRY_PROP_LAST_SUCCESS: // Last success + return (T)last_success; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + return (T) false; + }; + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_FLAG) _flag) { return action.Get(_flag); }; + template + bool Get(STRUCT_ENUM(TaskActionEntry, ENUM_TASK_ACTION_ENTRY_PROP) _prop) { + return action.Get(_prop); + }; + // bool Get(ENUM_TASK_ENTRY_FLAGS _flag) { return HasFlag(_flag); } + // TaskActionEntry GetAction() { return action; } + // TaskConditionEntry GetCondition() { return cond; } + // Setters. + template + void Set(ENUM_TASK_ENTRY_PROP _prop, T _value) { + switch (_prop) { + case TASK_ENTRY_PROP_EXPIRES: // Expires + expires = (T)_value; + case TASK_ENTRY_PROP_LAST_PROCESS: // Last process + last_process = (T)_value; + case TASK_ENTRY_PROP_LAST_SUCCESS: // Last success + last_success = (T)_value; + default: + SetUserError(ERR_INVALID_PARAMETER); + break; + } + }; // Flag methods. bool HasFlag(unsigned char _flag) { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -72,9 +120,9 @@ struct TaskEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. - // bool IsActive() { return HasFlag(ACTION_ENTRY_FLAG_IS_ACTIVE); } - // bool IsDone() { return HasFlag(ACTION_ENTRY_FLAG_IS_DONE); } - // bool IsFailed() { return HasFlag(ACTION_ENTRY_FLAG_IS_FAILED); } + bool IsActive() { return HasFlag(TASK_ENTRY_FLAG_IS_ACTIVE); } + bool IsDone() { return HasFlag(TASK_ENTRY_FLAG_IS_DONE); } + bool IsFailed() { return HasFlag(TASK_ENTRY_FLAG_IS_FAILED); } bool IsValid() { return action.IsValid() && cond.IsValid(); } // Getters. int GetActionId() { return action.GetId(); } diff --git a/Task/TaskObject.h b/Task/TaskObject.h index 38db316b9..b3f4650bb 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -38,7 +38,7 @@ #include "Task.h" template -class TaskObject : protected Task { +class TaskObject : public Task { protected: TaskAction action; TaskCondition condition; @@ -47,16 +47,36 @@ class TaskObject : protected Task { /* Special methods */ /** - * Class constructor. + * Default class constructor. */ - TaskObject(TaskActionEntry &_aentry, TaskConditionEntry &_centry) : action(_aentry), condition(_centry) {} + TaskObject() {} + + /** + * Class constructor with task entry as argument. + */ + TaskObject(TaskEntry &_tentry) : Task(_tentry) {} /** * Class deconstructor. */ ~TaskObject() {} - /* Main methods */ + /* Virtual methods */ + + /** + * Process tasks. + * + * @return + * Returns true when tasks has been processed. + */ + virtual bool Process() { + bool _result = true; + for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { + TaskEntry _entry = iter.Value(); + _result &= Process(_entry); + } + return _result; + } /** * Process task entry. @@ -64,9 +84,24 @@ class TaskObject : protected Task { * @return * Returns true when tasks has been processed. */ - static bool Process(TaskEntry &_entry) { + virtual bool Process(TaskEntry &_entry) { bool _result = false; - // @todo + if (_entry.IsActive()) { + if (condition.Check()) { + action.Run(); + _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); + if (_entry.IsDone()) { + _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_FAILED, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_FAILED))); + _entry.SetFlag(TASK_ENTRY_FLAG_IS_INVALID, + _entry.Get(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_INVALID))); + _entry.RemoveFlags(TASK_ENTRY_FLAG_IS_ACTIVE); + } + _result = true; + } + } return _result; } From 99cde57c20e584fae27019601a0b3b1a103de3a5 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 17 Jan 2022 21:20:51 +0000 Subject: [PATCH 82/97] Task: Adds TaskManager --- .github/workflows/test-task.yml | 1 + Task/TaskManager.h | 89 +++++++++++++++++++++++++++++ Task/tests/TaskManager.test.mq4 | 28 ++++++++++ Task/tests/TaskManager.test.mq5 | 99 +++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 Task/TaskManager.h create mode 100644 Task/tests/TaskManager.test.mq4 create mode 100644 Task/tests/TaskManager.test.mq5 diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 52dd9346f..fab47a667 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -52,6 +52,7 @@ jobs: - TaskAction.test - TaskCondition.test - TaskGetter.test + - TaskManager.test - TaskObject.test - TaskSetter.test - Taskable.car.test diff --git a/Task/TaskManager.h b/Task/TaskManager.h new file mode 100644 index 000000000..190f72ecb --- /dev/null +++ b/Task/TaskManager.h @@ -0,0 +1,89 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Provides task management. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Prevents processing this includes file for the second time. +#ifndef TASK_MANAGER_H +#define TASK_MANAGER_H + +// Includes. +#include "../DictObject.mqh" +#include "TaskObject.h" + +class TaskManager { + protected: + DictObject tasks; + // DictObject> tasks; + // DictObject> tasks; // @todo: Which one? + + /* Protected methods */ + + /** + * Init code (called on constructor). + */ + void Init() {} + + public: + /* Special methods */ + + /** + * Class constructor. + */ + TaskManager() { Init(); } + + /** + * Class deconstructor. + */ + ~TaskManager() {} + + /* Adder methods */ + + /** + * Adds new task. + */ + bool Add(Task &_task) { return tasks.Push(_task); } + + /* Processing methods */ + + /** + * Process tasks. + */ + bool Process() { + bool _result = true; + for (DictObjectIterator _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { + TaskObject *_task = _iter.Value(); + _result &= _task.Process(); + } + return _result; + } +}; + +#endif // TASK_MANAGER_H diff --git a/Task/tests/TaskManager.test.mq4 b/Task/tests/TaskManager.test.mq4 new file mode 100644 index 000000000..1092ba332 --- /dev/null +++ b/Task/tests/TaskManager.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskManager class. + */ + +// Includes. +#include "TaskManager.test.mq5" diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 new file mode 100644 index 000000000..a6c964df7 --- /dev/null +++ b/Task/tests/TaskManager.test.mq5 @@ -0,0 +1,99 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2022, EA31337 Ltd | +//| https://github.com/EA31337 | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of TaskManager class. + */ + +// Forward declaration. +struct DataParamEntry; + +// Includes. +#include "../../Test.mqh" +#include "../TaskManager.h" + +// Define test classes. +class ConditionType1 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ConditionType2 : public TaskConditionBase { + public: + bool Check(const TaskConditionEntry &_entry) { return true; } +}; +class ActionType1 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class ActionType2 : public TaskActionBase { + public: + bool Run(const TaskActionEntry &_entry) { return true; } +}; +class TaskType1 : public Taskable { + bool Check(const TaskConditionEntry &_entry) { return true; } + MqlParam Get(const TaskGetterEntry &_entry) { + MqlParam _result; + return _result; + } + bool Run(const TaskActionEntry &_entry) { return true; } + bool Set(const TaskSetterEntry &_entry, const MqlParam &_entry_value) { return true; } +}; + +// Test 1. +bool TestTaskManager01() { + bool _result = true; + TaskManager _tsm; + TaskActionEntry _aentry(1); + TaskConditionEntry _centry(1); + TaskEntry _tentry(_aentry, _centry); + TaskObject _task01(_tentry); + TaskObject _task02(_tentry); + TaskObject _task03(_tentry); + TaskObject _task04(_tentry); + _tsm.Add(_task01); + _tsm.Add(_task02); + _tsm.Add(_task03); + _tsm.Add(_task04); + _tsm.Process(); + // @todo: Print via ToString(). + return _result; +} + +/** + * Implements Init event handler. + */ +int OnInit() { + bool _result = true; + _result &= TestTaskManager01(); + _result &= GetLastError() == ERR_NO_ERROR; + return (_result ? INIT_SUCCEEDED : INIT_FAILED); +} + +/** + * Implements Tick event handler. + */ +void OnTick() {} + +/** + * Implements Deinit event handler. + */ +void OnDeinit(const int reason) {} From 32ec9558aba5be1e956982ab306b9ecffd2dff37 Mon Sep 17 00:00:00 2001 From: kenorb Date: Mon, 17 Jan 2022 23:28:22 +0000 Subject: [PATCH 83/97] Task/TaskObject: Adds support for objects --- Task/Task.struct.h | 4 ++-- Task/TaskAction.h | 4 ++-- Task/TaskCondition.h | 4 ++-- Task/TaskManager.h | 8 ++++++++ Task/TaskObject.h | 10 +++++----- Task/tests/TaskManager.test.mq5 | 20 ++++++++++++-------- Task/tests/TaskObject.test.mq5 | 18 +++++++++++------- 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/Task/Task.struct.h b/Task/Task.struct.h index f9cbf9815..2be699492 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -91,8 +91,8 @@ struct TaskEntry { return action.Get(_prop); }; // bool Get(ENUM_TASK_ENTRY_FLAGS _flag) { return HasFlag(_flag); } - // TaskActionEntry GetAction() { return action; } - // TaskConditionEntry GetCondition() { return cond; } + TaskActionEntry GetActionEntry() { return action; } + TaskConditionEntry GetConditionEntry() { return cond; } // Setters. template void Set(ENUM_TASK_ENTRY_PROP _prop, T _value) { diff --git a/Task/TaskAction.h b/Task/TaskAction.h index 4c647f98e..8fdf06693 100644 --- a/Task/TaskAction.h +++ b/Task/TaskAction.h @@ -47,7 +47,7 @@ class TaskAction : public TaskActionBase { protected: // Protected class variables. TaskActionEntry entry; // Action entry. - TO obj; // Object to run the action on. + TO *obj; // Object to run the action on. public: /* Special methods */ @@ -60,7 +60,7 @@ class TaskAction : public TaskActionBase { /** * Class constructor with an entry as argument. */ - TaskAction(TaskActionEntry &_entry) : entry(_entry) {} + TaskAction(TaskActionEntry &_entry, TO *_obj = NULL) : entry(_entry), obj(_obj) {} /* Main methods */ diff --git a/Task/TaskCondition.h b/Task/TaskCondition.h index 30214c373..0ae7e995b 100644 --- a/Task/TaskCondition.h +++ b/Task/TaskCondition.h @@ -48,7 +48,7 @@ class TaskCondition : public TaskConditionBase { protected: // Protected class variables. TaskConditionEntry entry; // Condition entry. - TO obj; // Object to run the action on. + TO *obj; // Object to run the action on. public: /* Special methods */ @@ -61,7 +61,7 @@ class TaskCondition : public TaskConditionBase { /** * Class constructor with an entry as argument. */ - TaskCondition(TaskConditionEntry &_entry) : entry(_entry) {} + TaskCondition(TaskConditionEntry &_entry, TO *_obj = NULL) : entry(_entry), obj(_obj) {} /* Main methods */ diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 190f72ecb..e886c6886 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -71,6 +71,14 @@ class TaskManager { */ bool Add(Task &_task) { return tasks.Push(_task); } + /** + * Adds new object task. + */ + template + bool Add(TaskObject &_task_obj) { + return tasks.Push(_task_obj); + } + /* Processing methods */ /** diff --git a/Task/TaskObject.h b/Task/TaskObject.h index b3f4650bb..f673f7945 100644 --- a/Task/TaskObject.h +++ b/Task/TaskObject.h @@ -40,8 +40,8 @@ template class TaskObject : public Task { protected: - TaskAction action; - TaskCondition condition; + TA *obja; + TC *objc; public: /* Special methods */ @@ -54,7 +54,7 @@ class TaskObject : public Task { /** * Class constructor with task entry as argument. */ - TaskObject(TaskEntry &_tentry) : Task(_tentry) {} + TaskObject(TaskEntry &_tentry, TA *_obja = NULL, TC *_objc = NULL) : obja(_obja), objc(_objc), Task(_tentry) {} /** * Class deconstructor. @@ -87,8 +87,8 @@ class TaskObject : public Task { virtual bool Process(TaskEntry &_entry) { bool _result = false; if (_entry.IsActive()) { - if (condition.Check()) { - action.Run(); + if (Object::IsValid(objc) && objc.Check(_entry.GetCondition()) && Object::IsValid(obja)) { + obja.Run(_entry.GetAction()); _entry.Set(STRUCT_ENUM(TaskEntry, TASK_ENTRY_PROP_LAST_PROCESS), TimeCurrent()); if (_entry.IsDone()) { _entry.SetFlag(TASK_ENTRY_FLAG_IS_DONE, diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index a6c964df7..51475dea2 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -61,18 +61,22 @@ class TaskType1 : public Taskable { // Test 1. bool TestTaskManager01() { bool _result = true; + ActionType1 _actionobj1; + ActionType2 _actionobj2; + ConditionType1 _condobj1; + ConditionType2 _condobj2; TaskManager _tsm; TaskActionEntry _aentry(1); TaskConditionEntry _centry(1); TaskEntry _tentry(_aentry, _centry); - TaskObject _task01(_tentry); - TaskObject _task02(_tentry); - TaskObject _task03(_tentry); - TaskObject _task04(_tentry); - _tsm.Add(_task01); - _tsm.Add(_task02); - _tsm.Add(_task03); - _tsm.Add(_task04); + TaskObject _taskobj01(_tentry, &_actionobj1, &_condobj1); + TaskObject _taskobj02(_tentry, &_actionobj2, &_condobj1); + TaskObject _taskobj03(_tentry, &_actionobj1, &_condobj2); + TaskObject _taskobj04(_tentry, &_actionobj2, &_condobj2); + _tsm.Add(_taskobj01); + _tsm.Add(_taskobj02); + _tsm.Add(_taskobj03); + _tsm.Add(_taskobj04); _tsm.Process(); // @todo: Print via ToString(). return _result; diff --git a/Task/tests/TaskObject.test.mq5 b/Task/tests/TaskObject.test.mq5 index c47a394ae..9cbe84c1a 100644 --- a/Task/tests/TaskObject.test.mq5 +++ b/Task/tests/TaskObject.test.mq5 @@ -61,13 +61,17 @@ class TaskType1 : public Taskable { // Test 1. bool TestTaskObject01() { bool _result = true; - TaskActionEntry _aentry; - TaskConditionEntry _centry; - // TaskAction _taction1; - // TaskAction _taction2; - // TaskCondition _tcond1; - // TaskCondition _tcond2; - TaskObject _task1(_aentry, _centry); + ActionType1 _actionobj1; + ActionType2 _actionobj2; + ConditionType1 _condobj1; + ConditionType2 _condobj2; + TaskActionEntry _aentry(1); + TaskConditionEntry _centry(1); + TaskEntry _tentry(_aentry, _centry); + TaskObject _taskobj01(_tentry, &_actionobj1, &_condobj1); + TaskObject _taskobj02(_tentry, &_actionobj2, &_condobj1); + TaskObject _taskobj03(_tentry, &_actionobj1, &_condobj2); + TaskObject _taskobj04(_tentry, &_actionobj2, &_condobj2); return _result; } From 8d748055c32cf21f9867bada0d0c265dabe8b9b7 Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Tue, 18 Jan 2022 18:08:17 +0100 Subject: [PATCH 84/97] Fixed DictObjectIterator's value pointer's cast. Fixed TaskEntry::Get()'s switch. Made tasks dictionary to store references to Task type. --- Task/Task.h | 2 +- Task/Task.struct.h | 3 +++ Task/TaskManager.h | 15 +++++++++------ Task/tests/TaskManager.test.mq5 | 20 ++++++++++++-------- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Task/Task.h b/Task/Task.h index 1f937672d..8bba0c7e1 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -42,7 +42,7 @@ #include "TaskCondition.h" #include "Taskable.h" -class Task : protected Taskable { +class Task : public Taskable { public: // Class variables. DictStruct tasks; diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 2be699492..81d8ba682 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -99,10 +99,13 @@ struct TaskEntry { switch (_prop) { case TASK_ENTRY_PROP_EXPIRES: // Expires expires = (T)_value; + break; case TASK_ENTRY_PROP_LAST_PROCESS: // Last process last_process = (T)_value; + break; case TASK_ENTRY_PROP_LAST_SUCCESS: // Last success last_success = (T)_value; + break; default: SetUserError(ERR_INVALID_PARAMETER); break; diff --git a/Task/TaskManager.h b/Task/TaskManager.h index e886c6886..7559f5ce5 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -40,7 +40,7 @@ class TaskManager { protected: - DictObject tasks; + DictStruct> tasks; // DictObject> tasks; // DictObject> tasks; // @todo: Which one? @@ -69,14 +69,17 @@ class TaskManager { /** * Adds new task. */ - bool Add(Task &_task) { return tasks.Push(_task); } + bool Add(Task *_task) { + Ref _ref = _task; + return tasks.Push(_ref); + } /** * Adds new object task. */ template - bool Add(TaskObject &_task_obj) { - return tasks.Push(_task_obj); + bool Add(TaskObject *_task_obj) { + return Add((Task *)_task_obj); } /* Processing methods */ @@ -86,8 +89,8 @@ class TaskManager { */ bool Process() { bool _result = true; - for (DictObjectIterator _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { - TaskObject *_task = _iter.Value(); + for (DictStructIterator> _iter = tasks.Begin(); _iter.IsValid(); ++_iter) { + Task *_task = _iter.Value().Ptr(); _result &= _task.Process(); } return _result; diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index 51475dea2..fa8fd72a9 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -69,14 +69,18 @@ bool TestTaskManager01() { TaskActionEntry _aentry(1); TaskConditionEntry _centry(1); TaskEntry _tentry(_aentry, _centry); - TaskObject _taskobj01(_tentry, &_actionobj1, &_condobj1); - TaskObject _taskobj02(_tentry, &_actionobj2, &_condobj1); - TaskObject _taskobj03(_tentry, &_actionobj1, &_condobj2); - TaskObject _taskobj04(_tentry, &_actionobj2, &_condobj2); - _tsm.Add(_taskobj01); - _tsm.Add(_taskobj02); - _tsm.Add(_taskobj03); - _tsm.Add(_taskobj04); + Ref> _taskobj01 = + new TaskObject(_tentry, &_actionobj1, &_condobj1); + Ref> _taskobj02 = + new TaskObject(_tentry, &_actionobj2, &_condobj1); + Ref> _taskobj03 = + new TaskObject(_tentry, &_actionobj1, &_condobj2); + Ref> _taskobj04 = + new TaskObject(_tentry, &_actionobj2, &_condobj2); + _tsm.Add(_taskobj01.Ptr()); + _tsm.Add(_taskobj02.Ptr()); + _tsm.Add(_taskobj03.Ptr()); + _tsm.Add(_taskobj04.Ptr()); _tsm.Process(); // @todo: Print via ToString(). return _result; From cb7cd42515f5a7ee4c8213258951416c2a03eb77 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 20:04:09 +0000 Subject: [PATCH 85/97] Strategy: Integrates TaskManager logic with Task's conditions --- EA.mqh | 2 - Strategy.enum.h | 1 - Strategy.mqh | 141 +++++++++--------------------------- Task/TaskCondition.struct.h | 2 +- 4 files changed, 35 insertions(+), 111 deletions(-) diff --git a/EA.mqh b/EA.mqh index 40e5b1610..ee368e1a7 100644 --- a/EA.mqh +++ b/EA.mqh @@ -374,8 +374,6 @@ class EA : public Taskable { } if (_strat.TickFilter(_tick)) { _can_trade &= !_strat.IsSuspended(); - _can_trade &= - !_strat.CheckCondition(STRAT_COND_TRADE_COND, TRADE_COND_HAS_STATE, TRADE_STATE_TRADE_CANNOT); TradeSignalEntry _sentry = GetStrategySignalEntry(_strat, _can_trade, _strat.Get(STRAT_PARAM_SHIFT)); if (_sentry.Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_SIGNALS)) > 0) { TradeSignal _signal(_sentry); diff --git a/Strategy.enum.h b/Strategy.enum.h index b3f60b197..1b54ffaf7 100644 --- a/Strategy.enum.h +++ b/Strategy.enum.h @@ -62,7 +62,6 @@ enum ENUM_STRATEGY_CONDITION { STRAT_COND_IS_SUSPENDED, // Strategy is suspended. STRAT_COND_IS_TREND, // Strategy is in trend. STRAT_COND_SIGNALOPEN, // On strategy's signal to open. - STRAT_COND_TRADE_COND, // On strategy's trade condition (args). FINAL_STRATEGY_CONDITION_ENTRY }; diff --git a/Strategy.mqh b/Strategy.mqh index 15ec64f03..5ae2df38b 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -36,7 +36,7 @@ class Trade; #include "Strategy.enum.h" #include "Strategy.struct.h" #include "String.mqh" -#include "Task/Task.h" +#include "Task/TaskManager.h" #include "Task/Taskable.h" #include "Trade.mqh" @@ -95,11 +95,11 @@ class Strategy : public Taskable { Dict fdata; Dict idata; DictStruct> indicators; // Indicators list. - DictStruct tasks; - Log logger; // Log instance. + Log logger; // Log instance. MqlTick last_tick; StgProcessResult sresult; Strategy *strat_sl, *strat_tp; // Strategy pointers for stop-loss and profit-take. + TaskManager tsm; // Tasks. Trade trade; // Trade instance. // TradeSignalEntry last_signal; // Last signals. @@ -163,46 +163,11 @@ class Strategy : public Taskable { StgProcessResult Process(unsigned short _periods_started = DATETIME_NONE) { sresult.last_error = ERR_NO_ERROR; if (_periods_started > 0) { - ProcessTasks(); + tsm.Process(); } return sresult; } - /* Tasks */ - - /** - * Add task. - */ - void AddTask(TaskEntry &_entry) { - if (_entry.IsValid()) { - /* @fixme - if (_entry.GetAction().GetType() == ACTION_TYPE_STRATEGY) { - _entry.SetActionObject(GetPointer(this)); - } - if (_entry.GetCondition().GetType() == COND_TYPE_STRATEGY) { - _entry.SetConditionObject(GetPointer(this)); - } - */ - tasks.Push(_entry); - } - } - - /** - * Process strategy's tasks. - * - * @return - * Returns StgProcessResult struct. - */ - void ProcessTasks() { - for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { - bool _is_processed = false; - TaskEntry _entry = iter.Value(); - _is_processed = Task::Process(_entry); - sresult.tasks_processed += (unsigned short)_is_processed; - sresult.tasks_processed_not += (unsigned short)!_is_processed; - } - } - /* State checkers */ /** @@ -674,74 +639,6 @@ class Strategy : public Taskable { return true; } - /* Conditions and actions */ - - /** - * Checks for Strategy condition. - * - * @param ENUM_STRATEGY_CONDITION _cond - * Strategy condition. - * @return - * Returns true when the condition is met. - */ - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = false; - long arg_size = ArraySize(_args); - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; - long _arg3l = ArraySize(_args) > 2 ? DataParamEntry::ToInteger(_args[2]) : WRONG_VALUE; - switch (_cond) { - case STRAT_COND_IS_ENABLED: - return sparams.IsEnabled(); - case STRAT_COND_IS_SUSPENDED: - return sparams.IsSuspended(); - case STRAT_COND_IS_TREND: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - return IsTrend((ENUM_ORDER_TYPE)_arg1l); - case STRAT_COND_SIGNALOPEN: { - ENUM_ORDER_TYPE _cmd = ArraySize(_args) > 1 ? (ENUM_ORDER_TYPE)_args[0].integer_value : ORDER_TYPE_BUY; - int _method = ArraySize(_args) > 1 ? (int)_args[1].integer_value : 0; - float _level = ArraySize(_args) > 2 ? (float)_args[2].double_value : 0; - return SignalOpen(_cmd, _method, _level); - } - case STRAT_COND_TRADE_COND: - // Args: - // 1st (i:0) - Trade's enum condition to check. - // 2rd... (i:1) - Optionally trade's arguments to pass. - if (arg_size > 0) { - DataParamEntry _sargs[]; - ArrayResize(_sargs, ArraySize(_args) - 1); - for (int i = 0; i < ArraySize(_sargs); i++) { - _sargs[i] = _args[i + 1]; - } - _result = trade.CheckCondition((ENUM_TRADE_CONDITION)_arg1l, _sargs); - } - return _result; - default: - GetLogger().Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - break; - } - return _result; - } - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Strategy::CheckCondition(_cond, _args); - } - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return Strategy::CheckCondition(_cond, _args); - } - bool CheckCondition(ENUM_STRATEGY_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return CheckCondition(_cond, _args); - } - /** * Execute Strategy action. * @@ -1255,6 +1152,25 @@ class Strategy : public Taskable { return _result; }; + /* Tasks methods */ + + /** + * Add task. + */ + bool AddTask(TaskEntry &_tentry) { + bool _is_valid = _tentry.IsValid(); + if (_is_valid) { + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tsm.Add(&_taskobj); + } + return _is_valid; + } + + /** + * Process tasks. + */ + void ProcessTasks() { tsm.Process(); } + /* Tasks */ /** @@ -1263,7 +1179,18 @@ class Strategy : public Taskable { virtual bool Check(const TaskConditionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case STRAT_COND_IS_ENABLED: + return sparams.IsEnabled(); + case STRAT_COND_IS_SUSPENDED: + return sparams.IsSuspended(); + case STRAT_COND_IS_TREND: + return IsTrend(_entry.GetArg(0).ToValue()); + case STRAT_COND_SIGNALOPEN: + return SignalOpen(_entry.GetArg(0).ToValue(), _entry.GetArg(1).ToValue(), + _entry.GetArg(2).ToValue()); default: + GetLogger().Error(StringFormat("Invalid EA condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 1485a49d7..abdc4f3a7 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -109,7 +109,7 @@ struct TaskConditionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - DataParamEntry GetArg(int _index) { return args[_index]; } + DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } From 66fda0d059c3e3a68a42b0ba30140b905f431a0d Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 20:23:47 +0000 Subject: [PATCH 86/97] Task: Fixes TaskAction test --- Task/tests/TaskAction.test.mq5 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Task/tests/TaskAction.test.mq5 b/Task/tests/TaskAction.test.mq5 index f1f0721af..981d8c760 100644 --- a/Task/tests/TaskAction.test.mq5 +++ b/Task/tests/TaskAction.test.mq5 @@ -68,14 +68,25 @@ class TaskActionTest02 : public TaskActionBase { int OnInit() { bool _result = true; // Test01 + TaskActionTest01 _atest01; TaskActionEntry _entry01(TASK_ACTION_TEST01); - TaskAction _action01(_entry01); + TaskAction _action01(_entry01, &_atest01); _action01.Run(); _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST02); _action01.Run(); _action01.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); _action01.Run(); assertTrueOrFail(_result && _action01.GetObject().GetSum() == 6, "Fail!"); + // Test02. + TaskActionTest02 _atest02; + TaskActionEntry _entry02(TASK_ACTION_TEST02); + TaskAction _action02(_entry02, &_atest02); + _action02.Run(); + _action02.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST02); + _action02.Run(); + _action02.Set(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_ID), TASK_ACTION_TEST03); + _action02.Run(); + assertTrueOrFail(_result && _action02.GetObject().GetSum() == 7, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From d6fb602f94df2662b0c36ccc3310e06db9eaee79 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 20:27:23 +0000 Subject: [PATCH 87/97] GHA: Includes testing on .mq? changes --- .github/workflows/test-task.yml | 2 ++ .github/workflows/test-trade.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index fab47a667..9890da617 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -6,10 +6,12 @@ on: pull_request: paths: - 'Task/**.h' + - 'Task/**.mq?' - '.github/workflows/test-task.yml' push: paths: - 'Task/**.h' + - 'Task/**.mq?' - '.github/workflows/test-task.yml' jobs: diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml index 4ab779efd..a3a9091ec 100644 --- a/.github/workflows/test-trade.yml +++ b/.github/workflows/test-trade.yml @@ -6,10 +6,12 @@ on: pull_request: paths: - 'Trade/**.h' + - 'Trade/**.mq?' - '.github/workflows/test-trade.yml' push: paths: - 'Trade/**.h' + - 'Trade/**.mq?' - '.github/workflows/test-trade.yml' jobs: From a975c3b4ffeda299d95f22531e39e04919892f7f Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 21:00:37 +0000 Subject: [PATCH 88/97] Task: Fixes TaskCondition test --- .github/workflows/test-task.yml | 6 ++---- Task/tests/TaskCondition.test.mq5 | 13 ++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 9890da617..faccb308a 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -5,13 +5,11 @@ name: Test Task on: pull_request: paths: - - 'Task/**.h' - - 'Task/**.mq?' + - 'Task/**' - '.github/workflows/test-task.yml' push: paths: - - 'Task/**.h' - - 'Task/**.mq?' + - 'Task/**' - '.github/workflows/test-task.yml' jobs: diff --git a/Task/tests/TaskCondition.test.mq5 b/Task/tests/TaskCondition.test.mq5 index ad8f241b0..30d96f5e4 100644 --- a/Task/tests/TaskCondition.test.mq5 +++ b/Task/tests/TaskCondition.test.mq5 @@ -68,14 +68,25 @@ class TaskConditionTest02 : public TaskConditionBase { int OnInit() { bool _result = true; // Test01 + TaskConditionTest01 _test01; TaskConditionEntry _entry01(TASK_CONDITION_TEST01); - TaskCondition _cond01(_entry01); + TaskCondition _cond01(_entry01, &_test01); _result &= _cond01.Check(); _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); _result &= _cond01.Check(); _cond01.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); _result &= _cond01.Check(); assertTrueOrFail(_result && _cond01.GetObject().GetSum() == 6, "Fail!"); + // Test02 + TaskConditionTest02 _test02; + TaskConditionEntry _entry02(TASK_CONDITION_TEST02); + TaskCondition _cond02(_entry02, &_test02); + _result &= _cond02.Check(); + _cond02.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST02); + _result &= _cond02.Check(); + _cond02.Set(STRUCT_ENUM(TaskConditionEntry, TASK_CONDITION_ENTRY_ID), TASK_CONDITION_TEST03); + _result &= _cond02.Check(); + assertTrueOrFail(_result && _cond01.GetObject().GetSum() == 6, "Fail!"); _result &= GetLastError() == ERR_NO_ERROR; return (_result ? INIT_SUCCEEDED : INIT_FAILED); } From 6dc2988d648005cd8c79b6dd2ba573635bff97ca Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 21:23:39 +0000 Subject: [PATCH 89/97] Strategy: Renames tsm to tasks --- Strategy.mqh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Strategy.mqh b/Strategy.mqh index 5ae2df38b..a84cc0588 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -99,7 +99,7 @@ class Strategy : public Taskable { MqlTick last_tick; StgProcessResult sresult; Strategy *strat_sl, *strat_tp; // Strategy pointers for stop-loss and profit-take. - TaskManager tsm; // Tasks. + TaskManager tasks; // Tasks. Trade trade; // Trade instance. // TradeSignalEntry last_signal; // Last signals. @@ -163,7 +163,7 @@ class Strategy : public Taskable { StgProcessResult Process(unsigned short _periods_started = DATETIME_NONE) { sresult.last_error = ERR_NO_ERROR; if (_periods_started > 0) { - tsm.Process(); + tasks.Process(); } return sresult; } @@ -1161,7 +1161,7 @@ class Strategy : public Taskable { bool _is_valid = _tentry.IsValid(); if (_is_valid) { TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); - tsm.Add(&_taskobj); + tasks.Add(&_taskobj); } return _is_valid; } @@ -1169,7 +1169,7 @@ class Strategy : public Taskable { /** * Process tasks. */ - void ProcessTasks() { tsm.Process(); } + void ProcessTasks() { tasks.Process(); } /* Tasks */ From 1388e1419c0fa023d76868f939ed83c680216d1e Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 21:34:44 +0000 Subject: [PATCH 90/97] EA: Integrates TaskManager logic with Task's conditions --- EA.mqh | 149 +++++++++++++++++++-------------------------------------- 1 file changed, 49 insertions(+), 100 deletions(-) diff --git a/EA.mqh b/EA.mqh index ee368e1a7..4c501ced6 100644 --- a/EA.mqh +++ b/EA.mqh @@ -44,7 +44,7 @@ #include "SerializerSqlite.mqh" #include "Strategy.mqh" #include "SummaryReport.mqh" -#include "Task/Task.h" +#include "Task/TaskManager.h" #include "Task/Taskable.h" #include "Terminal.mqh" #include "Trade.mqh" @@ -67,10 +67,10 @@ class EA : public Taskable { DictObject trade; DictObject> data_indi; DictObject> data_stg; - DictStruct tasks; EAParams eparams; EAProcessResult eresults; EAState estate; + TaskManager tasks; TradeSignalManager tsm; public: @@ -82,7 +82,7 @@ class EA : public Taskable { estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); UpdateStateFlags(); // Add and process tasks. - TaskAdd(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); + AddTask(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); ProcessTasks(); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); // Initialize a trade instance for the current chart and symbol. @@ -653,55 +653,6 @@ class EA : public Taskable { } */ - /* Tasks */ - - /** - * Add task. - */ - bool TaskAdd(TaskEntry &_entry) { - bool _result = false; - if (_entry.IsValid()) { - /* @fixme - switch (_entry.GetConditionId()) { - case COND_TYPE_ACCOUNT: - _entry.SetConditionObject(account); - break; - case COND_TYPE_EA: - _entry.SetConditionObject(THIS_PTR); - break; - case COND_TYPE_TRADE: - _entry.SetConditionObject(trade.GetByKey(_Symbol)); - break; - } - switch (_entry.GetActionId()) { - case ACTION_TYPE_EA: - _entry.SetActionObject(THIS_PTR); - break; - case ACTION_TYPE_TRADE: - _entry.SetActionObject(trade.GetByKey(_Symbol)); - break; - } - */ - _result |= tasks.Push(_entry); - } - return _result; - } - - /** - * Process EA tasks. - */ - unsigned int ProcessTasks() { - unsigned int _counter = 0; - for (DictStructIterator iter = tasks.Begin(); iter.IsValid(); ++iter) { - bool _is_processed = false; - TaskEntry _entry = iter.Value(); - _is_processed = _is_processed || Task::Process(_entry); - // _entry.last_process = TimeCurrent(); - _counter += (unsigned short)_is_processed; - } - return _counter; - } - /* Strategy methods */ /** @@ -868,53 +819,6 @@ class EA : public Taskable { return _result; } - /* Conditions and actions */ - - /** - * Checks for EA condition. - * - * @param ENUM_EA_CONDITION _cond - * EA condition. - * @return - * Returns true when the condition is met. - */ - bool CheckCondition(ENUM_EA_CONDITION _cond, DataParamEntry &_args[]) { - bool _result = false; - switch (_cond) { - case EA_COND_IS_ACTIVE: - return estate.IsActive(); - case EA_COND_IS_ENABLED: - return estate.IsEnabled(); - case EA_COND_IS_NOT_CONNECTED: - estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_CONNECTED), GetTerminal().IsConnected()); - return !estate.IsConnected(); - case EA_COND_ON_NEW_MINUTE: // On new minute. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0; - case EA_COND_ON_NEW_HOUR: // On new hour. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0; - case EA_COND_ON_NEW_DAY: // On new day. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0; - case EA_COND_ON_NEW_WEEK: // On new week. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0; - case EA_COND_ON_NEW_MONTH: // On new month. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0; - case EA_COND_ON_NEW_YEAR: // On new year. - return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0; - case EA_COND_ON_INIT: - return estate.IsOnInit(); - case EA_COND_ON_QUIT: - return estate.IsOnQuit(); - default: - logger.Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - break; - } - return _result; - } - bool CheckCondition(ENUM_EA_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return EA::CheckCondition(_cond, _args); - } - /** * Execute EA action. * @@ -952,7 +856,8 @@ class EA : public Taskable { return _result; case EA_ACTION_TASKS_CLEAN: // @todo - return tasks.Size() == 0; + // return tasks.Size() == 0; + return false; default: logger.Error(StringFormat("Invalid EA action: %s!", EnumToString(_action), __FUNCTION_LINE__)); return false; @@ -978,6 +883,25 @@ class EA : public Taskable { return EA::ExecuteAction(_action, _args); } + /* Tasks methods */ + + /** + * Add task. + */ + bool AddTask(TaskEntry &_tentry) { + bool _is_valid = _tentry.IsValid(); + if (_is_valid) { + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tasks.Add(&_taskobj); + } + return _is_valid; + } + + /** + * Process tasks. + */ + void ProcessTasks() { tasks.Process(); } + /* Tasks */ /** @@ -986,7 +910,32 @@ class EA : public Taskable { virtual bool Check(const TaskConditionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case EA_COND_IS_ACTIVE: + return estate.IsActive(); + case EA_COND_IS_ENABLED: + return estate.IsEnabled(); + case EA_COND_IS_NOT_CONNECTED: + estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_CONNECTED), GetTerminal().IsConnected()); + return !estate.IsConnected(); + case EA_COND_ON_NEW_MINUTE: // On new minute. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MINUTE) != 0; + case EA_COND_ON_NEW_HOUR: // On new hour. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_HOUR) != 0; + case EA_COND_ON_NEW_DAY: // On new day. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_DAY) != 0; + case EA_COND_ON_NEW_WEEK: // On new week. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_WEEK) != 0; + case EA_COND_ON_NEW_MONTH: // On new month. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_MONTH) != 0; + case EA_COND_ON_NEW_YEAR: // On new year. + return (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) & DATETIME_YEAR) != 0; + case EA_COND_ON_INIT: + return estate.IsOnInit(); + case EA_COND_ON_QUIT: + return estate.IsOnQuit(); default: + GetLogger().Error(StringFormat("Invalid EA condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; From a602b9d16dd771d9bee6f6fc5fad611e3cf530e0 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 22:28:41 +0000 Subject: [PATCH 91/97] Task: Adds struct methods for arguments --- Task/TaskAction.struct.h | 30 +++++++++++++++++++++++++----- Task/TaskCondition.struct.h | 33 ++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index ab7db5b16..d6a9210f1 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -78,7 +78,7 @@ struct TaskActionEntry { tries(-1) { Init(); } - TaskActionEntry(TaskActionEntry &_ae) { this = _ae; } + TaskActionEntry(TaskActionEntry &_ae) { THIS_REF = _ae; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -150,11 +150,31 @@ struct TaskActionEntry { } SetUserError(ERR_INVALID_PARAMETER); } - void AddArg(MqlParam &_arg) { - // @todo: Add another value to args[]. + // Methods for arguments. + void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } + void ArgsGet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(_args, ::ArraySize(args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + _args[i] = args[i]; + } + } + void ArgSet(DataParamEntry &_arg, int _index = 0) { + if (::ArraySize(args) <= _index) { + ::ArrayResize(args, _index + 1); + } + args[_index] = _arg; } - void SetArgs(ARRAY_REF(MqlParam, _args)) { - // @todo: for(). + void ArgsSet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(args, ::ArraySize(_args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + args[i] = _args[i]; + } + } + void ArgRemove(int _index) { + for (unsigned int i = 1; i < args.Size(); i++) { + ArgSet(args[i], i - 1); + } + ::ArrayResize(args, _index - 1); } // Serializers SerializerNodeType Serialize(Serializer &s) { diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index abdc4f3a7..8f890ac51 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -83,7 +83,7 @@ struct TaskConditionEntry { tries(-1) { Init(); } - TaskConditionEntry(TaskConditionEntry &_ae) { this = _ae; } + TaskConditionEntry(TaskConditionEntry &_ae) { THIS_REF = _ae; } // Deconstructor. void ~TaskConditionEntry() {} // Getters. @@ -143,6 +143,7 @@ struct TaskConditionEntry { } SetUserError(ERR_INVALID_PARAMETER); } + void SetTries(short _count) { tries = _count; } // Flag methods. bool HasFlag(unsigned char _flag) const { return bool(flags & _flag); } void AddFlags(unsigned char _flags) { flags |= _flags; } @@ -161,12 +162,30 @@ struct TaskConditionEntry { bool IsReady() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_READY); } bool IsInvalid() const { return HasFlag(TASK_CONDITION_ENTRY_FLAG_IS_INVALID); } bool IsValid() const { return !IsInvalid(); } - // Setters. - void AddArg(MqlParam &_arg) { - // @todo: Add another value to args[]. + // Methods for arguments. + void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } + void ArgsGet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(_args, ::ArraySize(args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + _args[i] = args[i]; + } } - void SetArgs(MqlParam &_args[]) { - // @todo: for(). + void ArgSet(DataParamEntry &_arg, int _index = 0) { + if (::ArraySize(args) <= _index) { + ::ArrayResize(args, _index + 1); + } + args[_index] = _arg; + } + void ArgsSet(ARRAY_REF(MqlParam, _args)) { + ::ArrayResize(args, ::ArraySize(_args)); + for (unsigned int i = 0; i < _args.Size(); i++) { + args[i] = _args[i]; + } + } + void ArgRemove(int _index) { + for (unsigned int i = 1; i < args.Size(); i++) { + ArgSet(args[i], i - 1); + } + ::ArrayResize(args, _index - 1); } - void SetTries(short _count) { tries = _count; } }; From c786bb6e0dbc24a04d36afef8e4c09f87bdf3928 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 22:41:43 +0000 Subject: [PATCH 92/97] EA/Strategy: Integrates taskable actions --- EA.mqh | 94 +++++++++------------------- Strategy.enum.h | 1 - Strategy.mqh | 120 +++++------------------------------- Task/TaskAction.struct.h | 10 +-- Task/TaskCondition.struct.h | 10 +-- 5 files changed, 53 insertions(+), 182 deletions(-) diff --git a/EA.mqh b/EA.mqh index 4c501ced6..4cef18cd0 100644 --- a/EA.mqh +++ b/EA.mqh @@ -819,70 +819,6 @@ class EA : public Taskable { return _result; } - /** - * Execute EA action. - * - * @param ENUM_EA_ACTION _action - * EA action to execute. - * @return - * Returns true when the action has been executed successfully. - */ - bool ExecuteAction(ENUM_EA_ACTION _action, DataParamEntry &_args[]) { - bool _result = false; - long arg_size = ArraySize(_args); - switch (_action) { - case EA_ACTION_DISABLE: - estate.Enable(false); - return true; - case EA_ACTION_ENABLE: - estate.Enable(); - return true; - case EA_ACTION_EXPORT_DATA: - DataExport(); - return true; - case EA_ACTION_STRATS_EXE_ACTION: - // Args: - // 1st (i:0) - Strategy's enum action to execute. - // 2nd (i:1) - Strategy's argument to pass. - for (DictStructIterator> iter_strat = strats.Begin(); iter_strat.IsValid(); ++iter_strat) { - DataParamEntry _sargs[]; - ArrayResize(_sargs, ArraySize(_args) - 1); - for (int i = 0; i < ArraySize(_sargs); i++) { - _sargs[i] = _args[i + 1]; - } - Strategy *_strat = iter_strat.Value().Ptr(); - _result &= _strat.ExecuteAction((ENUM_STRATEGY_ACTION)_args[0].integer_value, _sargs); - } - return _result; - case EA_ACTION_TASKS_CLEAN: - // @todo - // return tasks.Size() == 0; - return false; - default: - logger.Error(StringFormat("Invalid EA action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - return false; - } - return _result; - } - bool ExecuteAction(ENUM_EA_ACTION _action) { - ARRAY(DataParamEntry, _args); - return EA::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_EA_ACTION _action, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return EA::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_EA_ACTION _action, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return EA::ExecuteAction(_action, _args); - } - /* Tasks methods */ /** @@ -959,8 +895,36 @@ class EA : public Taskable { virtual bool Run(const TaskActionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case EA_ACTION_DISABLE: + estate.Enable(false); + return true; + case EA_ACTION_ENABLE: + estate.Enable(); + return true; + case EA_ACTION_EXPORT_DATA: + DataExport(); + return true; + case EA_ACTION_STRATS_EXE_ACTION: { + // Args: + // 1st (i:0) - Strategy's enum action to execute. + // 2nd (i:1) - Strategy's argument to pass. + TaskActionEntry _entry_strat = _entry; + _entry_strat.ArgRemove(0); + for (DictStructIterator> iter_strat = strats.Begin(); iter_strat.IsValid(); ++iter_strat) { + Strategy *_strat = iter_strat.Value().Ptr(); + + _result &= _strat.Run(_entry_strat); + } + return _result; + } + case EA_ACTION_TASKS_CLEAN: + // @todo + // return tasks.Size() == 0; + SetUserError(ERR_INVALID_PARAMETER); + return false; default: - break; + GetLogger().Error(StringFormat("Invalid EA action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); } return _result; } diff --git a/Strategy.enum.h b/Strategy.enum.h index 1b54ffaf7..defb9d4e2 100644 --- a/Strategy.enum.h +++ b/Strategy.enum.h @@ -51,7 +51,6 @@ enum ENUM_STRATEGY_ACTION { STRAT_ACTION_DISABLE = 0, // Disables strategy. STRAT_ACTION_ENABLE, // Enables strategy. STRAT_ACTION_SUSPEND, // Suspend Strategy. - STRAT_ACTION_TRADE_EXE, // Execute trade action. STRAT_ACTION_UNSUSPEND, // Unsuspend Strategy. FINAL_STRATEGY_ACTION_ENTRY }; diff --git a/Strategy.mqh b/Strategy.mqh index a84cc0588..0b694f7cc 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -639,112 +639,6 @@ class Strategy : public Taskable { return true; } - /** - * Execute Strategy action. - * - * @param ENUM_STRATEGY_ACTION _action - * Strategy action to execute. - * @param MqlParam _args - * Strategy action arguments. - * @return - * Returns true when the action has been executed successfully. - */ - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, DataParamEntry &_args[]) { - bool _result = false; - double arg1d = EMPTY_VALUE; - double arg2d = EMPTY_VALUE; - double arg3d = EMPTY_VALUE; - long arg1i = EMPTY; - long arg2i = EMPTY; - long arg3i = EMPTY; - long arg_size = ArraySize(_args); - if (arg_size > 0) { - arg1d = _args[0].type == TYPE_DOUBLE ? _args[0].double_value : EMPTY_VALUE; - arg1i = _args[0].type == TYPE_INT ? _args[0].integer_value : EMPTY; - if (arg_size > 1) { - arg2d = _args[1].type == TYPE_DOUBLE ? _args[1].double_value : EMPTY_VALUE; - arg2i = _args[1].type == TYPE_INT ? _args[1].integer_value : EMPTY; - } - if (arg_size > 2) { - arg3d = _args[2].type == TYPE_DOUBLE ? _args[2].double_value : EMPTY_VALUE; - arg3i = _args[2].type == TYPE_INT ? _args[2].integer_value : EMPTY; - } - } - switch (_action) { - case STRAT_ACTION_DISABLE: - sparams.Enabled(false); - return true; - case STRAT_ACTION_ENABLE: - sparams.Enabled(true); - return true; - case STRAT_ACTION_SUSPEND: - sparams.Suspended(true); - return true; - case STRAT_ACTION_TRADE_EXE: - // Args: - // 1st (i:0) - Trade's enum action to execute. - // 2rd (i:1) - Trade's argument to pass. - if (arg_size > 0) { - DataParamEntry _sargs[]; - ArrayResize(_sargs, ArraySize(_args) - 1); - for (int i = 0; i < ArraySize(_sargs); i++) { - _sargs[i] = _args[i + 1]; - } - _result = trade.ExecuteAction((ENUM_TRADE_ACTION)_args[0].integer_value, _sargs); - /* @fixme - if (_result) { - Order *_order = trade.GetOrderLast(); - switch ((ENUM_TRADE_ACTION)_args[0].integer_value) { - case TRADE_ACTION_ORDERS_CLOSE_BY_TYPE: - // OnOrderClose();// @todo - break; - case TRADE_ACTION_ORDER_OPEN: - // @fixme: Operation on the structure copy. - OnOrderOpen(_order.GetParams()); - break; - } - } - */ - } - return _result; - case STRAT_ACTION_UNSUSPEND: - sparams.Suspended(false); - return true; - default: - GetLogger().Error(StringFormat("Invalid Strategy action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - break; - } - return _result; - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Strategy::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return Strategy::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action, long _arg1, long _arg2, long _arg3) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - DataParamEntry _param3 = _arg3; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - ArrayPushObject(_args, _param3); - return Strategy::ExecuteAction(_action, _args); - } - bool ExecuteAction(ENUM_STRATEGY_ACTION _action) { - ARRAY(DataParamEntry, _args); - return Strategy::ExecuteAction(_action, _args); - } - /* Printers methods */ /** @@ -1214,7 +1108,21 @@ class Strategy : public Taskable { virtual bool Run(const TaskActionEntry &_entry) { bool _result = false; switch (_entry.GetId()) { + case STRAT_ACTION_DISABLE: + sparams.Enabled(false); + return true; + case STRAT_ACTION_ENABLE: + sparams.Enabled(true); + return true; + case STRAT_ACTION_SUSPEND: + sparams.Suspended(true); + return true; + case STRAT_ACTION_UNSUSPEND: + sparams.Suspended(false); + return true; default: + GetLogger().Error(StringFormat("Invalid Strategy action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index d6a9210f1..b0ca39f06 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -152,9 +152,9 @@ struct TaskActionEntry { } // Methods for arguments. void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } - void ArgsGet(ARRAY_REF(MqlParam, _args)) { + void ArgsGet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(_args, ::ArraySize(args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { _args[i] = args[i]; } } @@ -164,14 +164,14 @@ struct TaskActionEntry { } args[_index] = _arg; } - void ArgsSet(ARRAY_REF(MqlParam, _args)) { + void ArgsSet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(args, ::ArraySize(_args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { args[i] = _args[i]; } } void ArgRemove(int _index) { - for (unsigned int i = 1; i < args.Size(); i++) { + for (int i = 1; i < ::ArraySize(args); i++) { ArgSet(args[i], i - 1); } ::ArrayResize(args, _index - 1); diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 8f890ac51..49ddf4eec 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -164,9 +164,9 @@ struct TaskConditionEntry { bool IsValid() const { return !IsInvalid(); } // Methods for arguments. void ArgAdd(DataParamEntry &_arg) { ArgSet(_arg, ::ArraySize(args)); } - void ArgsGet(ARRAY_REF(MqlParam, _args)) { + void ArgsGet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(_args, ::ArraySize(args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { _args[i] = args[i]; } } @@ -176,14 +176,14 @@ struct TaskConditionEntry { } args[_index] = _arg; } - void ArgsSet(ARRAY_REF(MqlParam, _args)) { + void ArgsSet(ARRAY_REF(DataParamEntry, _args)) { ::ArrayResize(args, ::ArraySize(_args)); - for (unsigned int i = 0; i < _args.Size(); i++) { + for (int i = 0; i < ::ArraySize(_args); i++) { args[i] = _args[i]; } } void ArgRemove(int _index) { - for (unsigned int i = 1; i < args.Size(); i++) { + for (int i = 1; i < ::ArraySize(args); i++) { ArgSet(args[i], i - 1); } ::ArrayResize(args, _index - 1); From 2798a65fbe91e4cd510204ceac63b16c2857a7f4 Mon Sep 17 00:00:00 2001 From: kenorb Date: Sat, 22 Jan 2022 23:03:41 +0000 Subject: [PATCH 93/97] CompileTest: Adds missing Task includes --- tests/CompileTest.mq5 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 1f5648d64..2e9e76d69 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -100,6 +100,13 @@ #include "../SummaryReport.mqh" #include "../SymbolInfo.mqh" #include "../Task/Task.h" +#include "../Task/TaskAction.h" +#include "../Task/TaskCondition.h" +#include "../Task/TaskGetter.h" +#include "../Task/TaskManager.h" +#include "../Task/TaskObject.h" +#include "../Task/TaskSetter.h" +#include "../Task/Taskable.h" #include "../Terminal.mqh" // #include "../Tester.mqh" // @removeme #include "../Storage/ValueStorage.h" From 41d50e4675441a100f48feea8443bf8d9a7c952d Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 23 Jan 2022 00:09:09 +0000 Subject: [PATCH 94/97] Trade: Integrates TaskManager logic --- EA.mqh | 2 +- Strategy.mqh | 12 ++- Task/TaskAction.struct.h | 2 +- Trade.mqh | 153 ++++++++++++++++++++------------------- 4 files changed, 92 insertions(+), 77 deletions(-) diff --git a/EA.mqh b/EA.mqh index 4cef18cd0..43010c033 100644 --- a/EA.mqh +++ b/EA.mqh @@ -813,7 +813,7 @@ class EA : public Taskable { if (eparams.CheckFlag(EA_PARAM_FLAG_LOTSIZE_AUTO)) { // Auto calculate lot size for all strategies. Trade *_trade = trade.GetByKey(_Symbol); - _result &= _trade.ExecuteAction(TRADE_ACTION_CALC_LOT_SIZE); + _result &= _trade.Run(TRADE_ACTION_CALC_LOT_SIZE); Set(STRAT_PARAM_LS, _trade.Get(TRADE_PARAM_LOT_SIZE)); } return _result; diff --git a/Strategy.mqh b/Strategy.mqh index 0b694f7cc..dcdb4b081 100644 --- a/Strategy.mqh +++ b/Strategy.mqh @@ -855,9 +855,11 @@ class Strategy : public Taskable { if (METHOD(_method, 3)) _result &= !trade.HasOrderOppositeType(_cmd); // 8 if (METHOD(_method, 4)) _result &= trade.IsPeak(_cmd); // 16 if (METHOD(_method, 5)) _result &= !trade.HasOrderBetter(_cmd); // 32 + /* if (METHOD(_method, 6)) - _result &= !trade.CheckCondition( + _result &= !trade.Check( TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_LOW : ACCOUNT_COND_EQUITY_01PC_HIGH); // 64 + */ // if (METHOD(_method, 5)) _result &= Trade().IsRoundNumber(_cmd); // if (METHOD(_method, 6)) _result &= Trade().IsHedging(_cmd); _method = _method > 0 ? _method : !_method; @@ -962,10 +964,12 @@ class Strategy : public Taskable { _result |= _result || Open[_shift] > High[_shift + 1] || Open[_shift] < Low[_shift + 1]; // 8 if (METHOD(_method, 4)) _result |= _result || trade.IsPeak(_cmd); // 16 if (METHOD(_method, 5)) _result |= _result || trade.HasOrderBetter(_cmd); // 32 + /* if (METHOD(_method, 6)) _result |= - _result || trade.CheckCondition(TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_HIGH + _result || trade.Check(TRADE_COND_ACCOUNT, _method > 0 ? ACCOUNT_COND_EQUITY_01PC_HIGH : ACCOUNT_COND_EQUITY_01PC_LOW); // 64 + */ // if (METHOD(_method, 7)) _result |= _result || Trade().IsRoundNumber(_cmd); // if (METHOD(_method, 8)) _result |= _result || Trade().IsHedging(_cmd); _method = _method > 0 ? _method : !_method; @@ -1089,6 +1093,10 @@ class Strategy : public Taskable { } return _result; } + bool Check(int _id) { + TaskConditionEntry _entry(_id); + return Check(_entry); + } /** * Gets a copy of structure. diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index b0ca39f06..e82723fab 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -119,7 +119,7 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } - DataParamEntry GetArg(int _index) { return args[_index]; } + DataParamEntry GetArg(int _index) const { return args[_index]; } int GetId() const { return id; } // Setters. void TriesDec() { tries -= tries > 0 ? 1 : 0; } diff --git a/Trade.mqh b/Trade.mqh index 1d5a2a64e..021f29203 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -38,12 +38,12 @@ class Trade; #include "Object.mqh" #include "Order.mqh" #include "OrderQuery.h" -#include "Task/TaskAction.enum.h" -#include "Task/TaskCondition.enum.h" +#include "Task/TaskManager.h" +#include "Task/Taskable.h" #include "Trade.enum.h" #include "Trade.struct.h" -class Trade { +class Trade : public Taskable { public: Account account; Ref chart; @@ -51,6 +51,7 @@ class Trade { DictStruct> orders_history; DictStruct> orders_pending; Log logger; // Trade logger. + TaskManager tasks; // Tasks. TradeParams tparams; // Trade parameters. TradeStates tstates; // Trade states. TradeStats tstats; // Trade statistics. @@ -1716,44 +1717,49 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } } - /* Conditions */ + /* Tasks methods */ /** - * Checks for trade condition. - * - * @param ENUM_TRADE_CONDITION _cond - * Trade condition. - * @param MqlParam[] _args - * Condition arguments. - * @return - * Returns true when the condition is met. + * Add task. + */ + bool AddTask(TaskEntry &_tentry) { + bool _is_valid = _tentry.IsValid(); + if (_is_valid) { + TaskObject _taskobj(_tentry, THIS_PTR, THIS_PTR); + tasks.Add(&_taskobj); + } + return _is_valid; + } + + /** + * Process tasks. + */ + void ProcessTasks() { tasks.Process(); } + + /* Tasks */ + + /** + * Checks a condition. */ - bool CheckCondition(ENUM_TRADE_CONDITION _cond, DataParamEntry &_args[]) { + virtual bool Check(const TaskConditionEntry &_entry) { bool _result = false; - long _arg1l = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE; - long _arg2l = ArraySize(_args) > 1 ? DataParamEntry::ToInteger(_args[1]) : WRONG_VALUE; Ref _oquery_ref; if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _oquery_ref = OrderQuery::GetInstance(orders_active); } - switch (_cond) { + switch (_entry.GetId()) { case TRADE_COND_ACCOUNT: - return account.CheckCondition((ENUM_ACCOUNT_CONDITION)_args[0].integer_value); + return account.CheckCondition(_entry.GetArg(0).ToValue()); case TRADE_COND_ALLOWED_NOT: return !IsTradeAllowed(); case TRADE_COND_HAS_STATE: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - return HasState((ENUM_TRADE_STATE)_arg1l); + return HasState(_entry.GetArg(0).ToValue()); case TRADE_COND_IS_ORDER_LIMIT: return tparams.IsLimitGe(tstats); case TRADE_COND_IS_PEAK: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - _arg2l = _arg2l != WRONG_VALUE ? _arg2l : 0; - return IsPeak((ENUM_ORDER_TYPE)_arg1l, (int)_arg2l); + return IsPeak(_entry.GetArg(0).ToValue(), _entry.GetArg(1).ToValue()); case TRADE_COND_IS_PIVOT: - _arg1l = _arg1l != WRONG_VALUE ? _arg1l : 0; - _arg2l = _arg2l != WRONG_VALUE ? _arg2l : 0; - return IsPivot((ENUM_ORDER_TYPE)_arg1l, (int)_arg2l); + return IsPivot(_entry.GetArg(0).ToValue(), _entry.GetArg(1).ToValue()); case TRADE_COND_ORDERS_PROFIT_GT_01PC: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { return CalcActiveEquityInPct() >= 1; @@ -1797,41 +1803,39 @@ HistorySelect(0, TimeCurrent()); // Select history for access. // case TRADE_ORDER_CONDS_IN_TREND: // case TRADE_ORDER_CONDS_IN_TREND_NOT: default: - logger.Error(StringFormat("Invalid trade condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); + GetLogger().Error(StringFormat("Invalid Trade condition: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } return _result; } - bool CheckCondition(ENUM_TRADE_CONDITION _cond, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Trade::CheckCondition(_cond, _args); - } - bool CheckCondition(ENUM_TRADE_CONDITION _cond) { - ARRAY(DataParamEntry, _args); - return Trade::CheckCondition(_cond, _args); + bool Check(int _id) { + TaskConditionEntry _entry(_id); + return Check(_entry); } - /* TaskActions */ + /** + * Gets a copy of structure. + */ + virtual DataParamEntry Get(const TaskGetterEntry &_entry) { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + break; + } + return _result; + } /** - * Execute trade action. - * - * @param ENUM_TRADE_ACTION _action - * Trade action to execute. - * @param MqlParam _args - * Trade action arguments. - * @return - * Returns true when the condition is met. + * Runs an action. */ - bool ExecuteAction(ENUM_TRADE_ACTION _action, DataParamEntry &_args[]) { + virtual bool Run(const TaskActionEntry &_entry) { bool _result = false; Ref _oquery_ref; if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _oquery_ref = OrderQuery::GetInstance(orders_active); } - switch (_action) { + switch (_entry.GetId()) { case TRADE_ACTION_CALC_LOT_SIZE: tparams.Set(TRADE_PARAM_LOT_SIZE, CalcLotSize(tparams.Get(TRADE_PARAM_RISK_MARGIN))); return tparams.Get(TRADE_PARAM_LOT_SIZE) > 0; @@ -1870,7 +1874,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. } break; case TRADE_ACTION_ORDER_OPEN: - return RequestSend(GetTradeOpenRequest((ENUM_ORDER_TYPE)_args[0].integer_value)); + return RequestSend(GetTradeOpenRequest(_entry.GetArg(0).ToValue())); case TRADE_ACTION_ORDERS_CLOSE_ALL: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { _result = OrdersCloseAll(ORDER_REASON_CLOSED_BY_ACTION) >= 0; @@ -1899,7 +1903,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_CLOSE_BY_TYPE: if (Get(TRADE_STATE_ORDERS_ACTIVE)) { - _result = OrdersCloseViaCmd((ENUM_ORDER_TYPE)_args[0].integer_value, ORDER_REASON_CLOSED_BY_ACTION) >= 0; + _result = OrdersCloseViaCmd(_entry.GetArg(0).ToValue(), ORDER_REASON_CLOSED_BY_ACTION) >= 0; RefreshActiveOrders(true); } break; @@ -1926,37 +1930,36 @@ HistorySelect(0, TimeCurrent()); // Select history for access. break; case TRADE_ACTION_ORDERS_LIMIT_SET: // Sets the new limits. - tparams.SetLimits((ENUM_TRADE_STAT_TYPE)_args[0].integer_value, (ENUM_TRADE_STAT_PERIOD)_args[1].integer_value, - (int)_args[2].integer_value); + tparams.SetLimits(_entry.GetArg(0).ToValue(), + _entry.GetArg(1).ToValue(), _entry.GetArg(2).ToValue()); // Verify the new limits. - return tparams.GetLimits((ENUM_TRADE_STAT_TYPE)_args[0].integer_value, - (ENUM_TRADE_STAT_PERIOD)_args[1].integer_value) == _args[2].integer_value; + return tparams.GetLimits(_entry.GetArg(0).ToValue(), + _entry.GetArg(1).ToValue()) == _entry.GetArg(2).ToValue(); case TRADE_ACTION_STATE_ADD: - tstates.AddState((unsigned int)_args[0].integer_value); + tstates.AddState(_entry.GetArg(0).ToValue()); default: - logger.Error(StringFormat("Invalid trade action: %s!", EnumToString(_action), __FUNCTION_LINE__)); - _result = false; + GetLogger().Error(StringFormat("Invalid Trade action: %d!", _entry.GetId(), __FUNCTION_LINE__)); + SetUserError(ERR_INVALID_PARAMETER); break; } - return _result && GetLastError() == ERR_NO_ERROR; - } - bool ExecuteAction(ENUM_TRADE_ACTION _action) { - DataParamEntry _args[]; - return Trade::ExecuteAction(_action, _args); + return _result; } - bool ExecuteAction(ENUM_TRADE_ACTION _action, long _arg1) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - ArrayPushObject(_args, _param1); - return Trade::ExecuteAction(_action, _args); + bool Run(int _id) { + TaskActionEntry _entry(_id); + return Run(_entry); } - bool ExecuteAction(ENUM_TRADE_ACTION _action, long _arg1, long _arg2) { - ARRAY(DataParamEntry, _args); - DataParamEntry _param1 = _arg1; - DataParamEntry _param2 = _arg2; - ArrayPushObject(_args, _param1); - ArrayPushObject(_args, _param2); - return Trade::ExecuteAction(_action, _args); + + /** + * Sets an entry value. + */ + virtual bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) { + bool _result = false; + switch (_entry.GetId()) { + // _entry_value.GetValue() + default: + break; + } + return _result; } /* Printer methods */ @@ -1964,7 +1967,11 @@ HistorySelect(0, TimeCurrent()); // Select history for access. /** * Returns textual representation of the Trade class. */ - string ToString() { return StringFormat("Margin required: %g/lot", GetMarginRequired()); } + string ToString() const { + // @todo + // return StringFormat("Margin required: %g/lot", GetMarginRequired()); + return ""; + } /* Class handlers */ From 61b201cc0cfc402546efb63947844162f338a1bb Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 23 Jan 2022 13:10:30 +0000 Subject: [PATCH 95/97] EA: Reenables initial task logic --- EA.mqh | 24 ++++++++++++++++++++---- EA.struct.h | 2 +- tests/EATest.mq5 | 6 +++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/EA.mqh b/EA.mqh index 43010c033..360d6aa2a 100644 --- a/EA.mqh +++ b/EA.mqh @@ -73,18 +73,34 @@ class EA : public Taskable { TaskManager tasks; TradeSignalManager tsm; + protected: + /* Protected methods */ + + /** + * Init code (called on constructor). + */ + void Init() { InitTask(); } + + /** + * Process initial task (called on constructor). + */ + void InitTask() { + // Add and process init task. + TaskObject _taskobj_init(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); + estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); + _taskobj_init.Process(); + estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); + } + public: /** * Class constructor. */ EA(EAParams &_params) : account(new Account) { eparams = _params; - estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); UpdateStateFlags(); // Add and process tasks. - AddTask(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); - ProcessTasks(); - estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); + Init(); // Initialize a trade instance for the current chart and symbol. ChartParams _cparams((ENUM_TIMEFRAMES)_Period, _Symbol); TradeParams _tparams; diff --git a/EA.struct.h b/EA.struct.h index ce30ff70d..5bed4845d 100644 --- a/EA.struct.h +++ b/EA.struct.h @@ -195,7 +195,7 @@ struct EAParams { ver = _ver; author = _author; } - // void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } + void SetTaskEntry(TaskEntry &_task_entry) { task_init = _task_entry; } // Printers. string ToString(string _dlm = ",") { return StringFormat("%s v%s by %s (%s)", name, ver, author, desc); } }; diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 176be0a21..31d11e524 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -59,7 +59,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - //ea_params.SetTaskEntry(_task_export_per_hour); + ea_params.SetTaskEntry(_task_export_per_hour); ea = new EA(ea_params); assertTrueOrFail(ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA", StringFormat("Invalid EA name: %s!", ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); @@ -69,7 +69,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - //ea_params1.SetTaskEntry(_task_export_per_hour); + ea_params1.SetTaskEntry(_task_export_per_hour); ea1 = new EA1(ea_params1); assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", "Invalid EA1 name!"); @@ -78,7 +78,7 @@ int OnInit() { // Exporting to all possible formats once per hour. ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - //ea_params2.SetTaskEntry(_task_export_per_hour); + ea_params2.SetTaskEntry(_task_export_per_hour); ea2 = new EA2(ea_params2); assertTrueOrFail(ea2.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA2", "Invalid EA2 name!"); From 2d6c6cf72615a6b7f794381c73de6d0574cd9eba Mon Sep 17 00:00:00 2001 From: kenorb Date: Sun, 23 Jan 2022 14:19:29 +0000 Subject: [PATCH 96/97] EA: Adds test for task init --- EA.mqh | 3 ++- tests/EATest.mq5 | 35 ++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/EA.mqh b/EA.mqh index 360d6aa2a..d663ceff2 100644 --- a/EA.mqh +++ b/EA.mqh @@ -86,7 +86,8 @@ class EA : public Taskable { */ void InitTask() { // Add and process init task. - TaskObject _taskobj_init(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); + TaskObject _taskobj_init(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY)), + THIS_PTR, THIS_PTR); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); _taskobj_init.Process(); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 31d11e524..96eb8238f 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -42,10 +42,15 @@ class EA2 : public EA { EA2(EAParams &_params) : EA(_params) {} }; +class EA3 : public EA { + public: + EA3(EAParams &_params) : EA(_params) {} +}; + // Global variables. -EA *ea; EA1 *ea1; EA2 *ea2; +EA3 *ea3; /** * Implements OnInit(). @@ -54,16 +59,6 @@ int OnInit() { // Task to export to all possible formats once per hour. TaskEntry _task_export_per_hour(EA_ACTION_EXPORT_DATA, EA_COND_ON_NEW_HOUR); - /* Initialize base class EA */ - EAParams ea_params("EA"); - // Exporting to all possible formats once per hour. - ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); - ea_params.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); - ea_params.SetTaskEntry(_task_export_per_hour); - ea = new EA(ea_params); - assertTrueOrFail(ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA", - StringFormat("Invalid EA name: %s!", ea.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); - /* Initialize 1st custom EA */ EAParams ea_params1("EA1"); // Exporting to all possible formats once per hour. @@ -71,9 +66,11 @@ int OnInit() { ea_params1.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_EXPORT), EA_DATA_EXPORT_ALL); ea_params1.SetTaskEntry(_task_export_per_hour); ea1 = new EA1(ea_params1); - assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", "Invalid EA1 name!"); + assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA1", + StringFormat("Invalid EA name: %s!", ea1.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)))); + assertTrueOrFail(ea1.Get(STRUCT_ENUM(EAState, EA_STATE_FLAG_ENABLED)), "EA should be enabled by default!"); - /* Initialize 2st custom EA */ + /* Initialize 2nd custom EA */ EAParams ea_params2("EA2"); // Exporting to all possible formats once per hour. ea_params2.Set(STRUCT_ENUM(EAParams, EA_PARAM_PROP_DATA_STORE), EA_DATA_STORE_ALL); @@ -82,6 +79,14 @@ int OnInit() { ea2 = new EA2(ea_params2); assertTrueOrFail(ea2.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_NAME)) == "EA2", "Invalid EA2 name!"); + /* Initialize 3rd custom EA */ + EAParams ea_params3("EA3"); + // Create an init task to disable EA when enabled. + TaskEntry _tentry_ea_disable(EA_ACTION_DISABLE, EA_COND_IS_ENABLED); + ea_params3.SetTaskEntry(_tentry_ea_disable); + ea3 = new EA3(ea_params3); + assertTrueOrFail(!ea3.Get(STRUCT_ENUM(EAState, EA_STATE_FLAG_ENABLED)), "EA should be disabled by a task!"); + return (INIT_SUCCEEDED); } @@ -89,16 +94,16 @@ int OnInit() { * Implements OnTick(). */ void OnTick() { - ea.ProcessTick(); ea1.ProcessTick(); ea2.ProcessTick(); + ea3.ProcessTick(); } /** * Implements OnDeinit(). */ void OnDeinit(const int reason) { - delete ea; delete ea1; delete ea2; + delete ea3; } From 6941c25b41b2b60f8a833ad3595464836db5771f Mon Sep 17 00:00:00 2001 From: Adrian Kierzkowski Date: Wed, 26 Jan 2022 17:55:49 +0100 Subject: [PATCH 97/97] Added TaskManager::Add(string _entry) method which creates TaskEntry from JSON string. --- SerializerConverter.mqh | 4 ++++ Task/Task.struct.h | 9 +++++++++ Task/TaskCondition.struct.h | 15 +++++++++++++++ Task/TaskManager.h | 13 +++++++++++++ Task/tests/TaskManager.test.mq5 | 4 ++++ 5 files changed, 45 insertions(+) diff --git a/SerializerConverter.mqh b/SerializerConverter.mqh index 37753e76d..f9076e71d 100644 --- a/SerializerConverter.mqh +++ b/SerializerConverter.mqh @@ -84,6 +84,10 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { SerializerConverter _converter(((C*)NULL).Parse(arg), 0); +#ifdef __debug__ + Print("FromString(): result: ", + _converter.Node() != NULL ? _converter.Node().ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); +#endif return _converter; } diff --git a/Task/Task.struct.h b/Task/Task.struct.h index 81d8ba682..d9ab789c5 100644 --- a/Task/Task.struct.h +++ b/Task/Task.struct.h @@ -132,4 +132,13 @@ struct TaskEntry { int GetConditionId() { return cond.GetId(); } TaskActionEntry GetAction() { return action; } TaskConditionEntry GetCondition() { return cond; } + + public: + SerializerNodeType Serialize(Serializer &s) { + s.PassStruct(THIS_REF, "aentry", action); + s.PassStruct(THIS_REF, "centry", cond); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskCondition.struct.h b/Task/TaskCondition.struct.h index 49ddf4eec..24df55dc7 100644 --- a/Task/TaskCondition.struct.h +++ b/Task/TaskCondition.struct.h @@ -188,4 +188,19 @@ struct TaskConditionEntry { } ::ArrayResize(args, _index - 1); } + + public: + // Serializers + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "flags", flags); + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "last_check", last_check); + s.Pass(THIS_REF, "last_success", last_success); + s.Pass(THIS_REF, "tries", tries); + s.PassEnum(THIS_REF, "freq", freq); + s.PassArray(this, "args", args); + return SerializerNodeObject; + } + + SERIALIZER_EMPTY_STUB; }; diff --git a/Task/TaskManager.h b/Task/TaskManager.h index 7559f5ce5..2ae9dd44f 100644 --- a/Task/TaskManager.h +++ b/Task/TaskManager.h @@ -36,6 +36,9 @@ // Includes. #include "../DictObject.mqh" +#include "../SerializerConverter.mqh" +#include "../SerializerJson.mqh" +#include "Task.struct.h" #include "TaskObject.h" class TaskManager { @@ -74,6 +77,16 @@ class TaskManager { return tasks.Push(_ref); } + /** + * Adds new task. + */ + bool Add(string _entry_str) { + TaskEntry _entry; + SerializerConverter::FromString(_entry_str).ToObject(_entry); + Ref _task = new Task(_entry); + return Add(_task.Ptr()); + } + /** * Adds new object task. */ diff --git a/Task/tests/TaskManager.test.mq5 b/Task/tests/TaskManager.test.mq5 index fa8fd72a9..4ade617b8 100644 --- a/Task/tests/TaskManager.test.mq5 +++ b/Task/tests/TaskManager.test.mq5 @@ -81,6 +81,10 @@ bool TestTaskManager01() { _tsm.Add(_taskobj02.Ptr()); _tsm.Add(_taskobj03.Ptr()); _tsm.Add(_taskobj04.Ptr()); + + // @todo: Need a way to test if object was added properly. + _tsm.Add("{\"aentry\": {\"id\": 1}, \"centry\": {\"id\": 2}}"); + _tsm.Process(); // @todo: Print via ToString(). return _result;