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/.github/workflows/test-task.yml b/.github/workflows/test-task.yml
new file mode 100644
index 000000000..faccb308a
--- /dev/null
+++ b/.github/workflows/test-task.yml
@@ -0,0 +1,67 @@
+---
+name: Test Task
+
+# yamllint disable-line rule:truthy
+on:
+ pull_request:
+ paths:
+ - 'Task/**'
+ - '.github/workflows/test-task.yml'
+ push:
+ paths:
+ - 'Task/**'
+ - '.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
+ - TaskGetter.test
+ - TaskManager.test
+ - TaskObject.test
+ - TaskSetter.test
+ - Taskable.car.test
+ - Taskable.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 }}
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 }}
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:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7e9f32e28..7040970bc 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -27,7 +27,7 @@ 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
run: '(Get-ChildItem -Recurse -Path . -Include *.ex[45]).fullname'
@@ -54,12 +54,10 @@ jobs:
matrix:
test:
- AccountTest
- - ActionTest
- BufferStructTest
- BufferTest
- ChartTest
- CompileIndicatorsTest
- - ConditionTest
- DatabaseTest
- DrawIndicatorTest
- EATest
@@ -76,7 +74,6 @@ jobs:
- StrategyTest-RSI
- SymbolInfoTest
- SummaryReportTest
- - TaskTest
- TickerTest
- TradeTest
steps:
@@ -89,6 +86,7 @@ jobs:
BtDays: 1-8
BtMonths: 1
BtYears: 2020
+ MtVersion: 4.0.0.1349
TestExpert: ${{ matrix.test }}
timeout-minutes: 10
@@ -102,6 +100,7 @@ jobs:
strategy:
matrix:
test:
+ # - 3DTest
- CollectionTest
- ConfigTest
- ConvertTest
diff --git a/3D/Chart3D.h b/3D/Chart3D.h
new file mode 100644
index 000000000..aedfdbe05
--- /dev/null
+++ b/3D/Chart3D.h
@@ -0,0 +1,225 @@
+//+------------------------------------------------------------------+
+//| 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 "../Bar.struct.h"
+#include "../Indicators/Indi_MA.mqh"
+#include "../Instances.h"
+#include "../Refs.mqh"
+#include "../SerializerConverter.mqh"
+#include "../SerializerJson.mqh"
+#include "Chart3DCandles.h"
+#include "Chart3DType.h"
+#include "Cube.h"
+#include "Device.h"
+#include "Interface.h"
+
+#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);
+
+// Type of the currently rendered 3d chart.
+enum ENUM_CHART3D_TYPE {
+ CHART3D_TYPE_BARS,
+ CHART3D_TYPE_CANDLES,
+ CHART3D_TYPE_LINES,
+};
+
+class Chart3D;
+
+void chart3d_interface_listener(InterfaceEvent& _event, void* _target) {
+ Chart3D* chart3d = (Chart3D*)_target;
+ chart3d.OnInterfaceEvent(_event);
+}
+
+/**
+ * 3D chart renderer.
+ */
+class Chart3D : public Dynamic {
+ // 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;
+
+ Chart3DType* current_renderer;
+
+ Instances instances;
+
+ public:
+ /**
+ * Constructor.
+ */
+ 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;
+#ifdef __MQL5__
+ Interface::AddListener(chart3d_interface_listener, &this);
+#endif
+ }
+
+ 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) {
+ // 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;
+ }
+ }
+
+ current_renderer = renderers[type].Ptr();
+
+ return renderers[type].Ptr();
+ }
+
+ /**
+ * Returns given bar's OHLC.
+ */
+ 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.
+ */
+ 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() {
+ 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()));
+ }
+
+ /**
+ * Returns number of bars that are visible on te screen.
+ */
+ int GetBarsVisibleCount() { return GetBarsVisibleShiftStart() - GetBarsVisibleShiftEnd() + 1; }
+
+ /**
+ * 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 = 40.0f;
+ float _price_min = GetMinBarsPrice();
+ float _price_max = GetMaxBarsPrice();
+ float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y - (_scale_y / 2);
+ return _result;
+ }
+
+ /**
+ * Renders chart.
+ */
+ void Render(Device* _device) {
+ Chart3DType* _type_renderer = GetRenderer(_device);
+
+ BarOHLC _ohlc;
+ // BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); // @fixme: 'price_fetcher' - internal error #%d
+
+#ifdef __debug__
+ Print(SerializerConverter::FromObject(_ohlc).ToString());
+#endif
+
+ _type_renderer.Render(_device);
+ }
+};
diff --git a/3D/Chart3DCandles.h b/3D/Chart3DCandles.h
new file mode 100644
index 000000000..1340d9be5
--- /dev/null
+++ b/3D/Chart3DCandles.h
@@ -0,0 +1,103 @@
+//+------------------------------------------------------------------+
+//| 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 "Cube.h"
+#include "Device.h"
+#include "Vertex.h"
+
+class Chart3D;
+
+/**
+ * 3D chart candles renderer.
+ */
+class Chart3DCandles : public Chart3DType {
+ Ref> cube1;
+ Ref> cube2;
+ Ref> cube3;
+
+ public:
+ /**
+ * Constructor.
+ */
+ Chart3DCandles(Chart3D* _chart3d, Device* _device) : Chart3DType(_chart3d, _device) {
+ cube1 = new Cube(1.0f, 1.0f, 1.0f);
+ cube2 = new Cube(0.10f, 1.0f, 0.10f);
+ cube3 = new Cube(1.0f, 0.075f, 0.075f);
+ }
+
+ /**
+ * Renders chart.
+ */
+ virtual void Render(Device* _device) {
+ TSR _tsr;
+
+ 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.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());
+
+ 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(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());
+ }
+ }
+};
diff --git a/3D/Chart3DType.h b/3D/Chart3DType.h
new file mode 100644
index 000000000..9e49737f7
--- /dev/null
+++ b/3D/Chart3DType.h
@@ -0,0 +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
+ * 3D chart type renderer.
+ */
+
+#include "../Refs.mqh"
+#include "Device.h"
+
+class Chart3D;
+class Device;
+
+/**
+ * 3D chart type renderer.
+ */
+class Chart3DType : public Dynamic {
+ protected:
+ Chart3D* chart3d;
+ Device* device;
+
+ public:
+ /**
+ * Constructor.
+ */
+ Chart3DType(Chart3D* _chart3d, Device* _device) : chart3d(_chart3d), device(_device) {}
+
+ Device* GetDevice() { return device; }
+
+ /**
+ * Renders chart.
+ */
+ virtual void Render(Device* _device) {}
+};
diff --git a/3D/Cube.h b/3D/Cube.h
new file mode 100644
index 000000000..0bc9038ff
--- /dev/null
+++ b/3D/Cube.h
@@ -0,0 +1,84 @@
+//+------------------------------------------------------------------+
+//| 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"
+
+#ifdef __MQL5__
+// Resource variables.
+#resource "Shaders/cube_ps.hlsl" as string ShaderCubeSourcePS;
+#resource "Shaders/cube_vs.hlsl" as string ShaderCubeSourceVS;
+#endif
+
+/**
+ * Cube mesh.
+ */
+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)
+ : Mesh(MESH_TYPE_SEPARATE_POINTS) {
+ 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);
+ }
+
+#ifdef __MQL5__
+ /**
+ * Initializes graphics device-related things.
+ */
+ virtual void Initialize(Device* _device) {
+ SetShaderVS(_device.VertexShader(ShaderCubeSourceVS, T::Layout));
+ SetShaderPS(_device.PixelShader(ShaderCubeSourcePS));
+ }
+#endif
+};
diff --git a/3D/Device.h b/3D/Device.h
new file mode 100644
index 000000000..d7b64f94f
--- /dev/null
+++ b/3D/Device.h
@@ -0,0 +1,312 @@
+//+------------------------------------------------------------------+
+//| 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 "../Util.h"
+#include "Frontend.h"
+#include "IndexBuffer.h"
+#include "Material.h"
+#include "Math.h"
+#include "Mesh.h"
+#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 };
+
+/**
+ * Graphics device.
+ */
+class Device : public Dynamic {
+ protected:
+ int context;
+ Ref frontend;
+ DXMatrix mtx_stack[];
+ DXMatrix mtx_world;
+ DXMatrix mtx_view;
+ DXMatrix mtx_projection;
+ DXVector3 lightdir;
+ Material material;
+
+ public:
+ /**
+ * Initializes graphics device.
+ */
+ 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) {
+ Util::ArrayPush(mtx_stack, mtx_world);
+ DXMatrixMultiply(mtx_world, tsr.ToMatrix(), mtx_world);
+ }
+
+ void PopTransform() { mtx_world = Util::ArrayPop(mtx_stack); }
+
+ /**
+ * Begins render loop.
+ */
+ Device* Begin(unsigned int clear_color = 0) {
+ frontend.Ptr().RenderBegin(context);
+ Clear(clear_color);
+ ClearDepth();
+ RenderBegin();
+ return &this;
+ }
+
+ /**
+ * Ends render loop.
+ */
+ Device* End() {
+ RenderEnd();
+ frontend.Ptr().RenderEnd(context);
+ frontend.Ptr().ProcessDrawText();
+ 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 current material.
+ */
+ Material GetMaterial() { return material; }
+
+ /**
+ * Assigns material for later rendering.
+ */
+ void SetMaterial(Material& _material) { material = _material; }
+
+ /**
+ * Returns graphics device context as integer.
+ */
+ int Context() { return context; }
+
+ /**
+ * 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.
+ */
+ template
+ VertexBuffer* VertexBuffer(T& data[]) {
+ VertexBuffer* _buff = VertexBuffer();
+ // Unfortunately we can't make this method virtual.
+ if (dynamic_cast(_buff) != NULL) {
+// MT5's DirectX.
+#ifdef __debug__
+ Print("Filling vertex buffer via MTDXVertexBuffer");
+#endif
+ ((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;
+
+ /**
+ * Creates index buffer to be used by current graphics device.
+ */
+ virtual IndexBuffer* IndexBuffer(unsigned int& _indices[]) = NULL;
+
+ /**
+ * Renders vertex buffer with optional point indices.
+ */
+ 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, Shader* _vs = NULL, Shader* _ps = NULL) {
+#ifdef __debug__
+ Print("Rendering mesh");
+#endif
+ VertexBuffer* _vertices;
+ IndexBuffer* _indices;
+ _mesh.GetBuffers(&this, _vertices, _indices);
+
+ SetMaterial(_mesh.GetMaterial());
+
+ PushTransform(_mesh.GetTSR());
+
+ SetShader(_vs != NULL ? _vs : _mesh.GetShaderVS());
+ SetShader(_ps != NULL ? _ps : _mesh.GetShaderPS());
+
+ Render(_vertices, _indices);
+
+ PopTransform();
+ }
+
+ /**
+ * Activates shader for rendering.
+ */
+ void SetShader(Shader* _shader) { _shader.Select(); }
+
+ /**
+ * Activates shaders for rendering.
+ */
+ void SetShader(Shader* _shader1, Shader* _shader2) {
+ _shader1.Select();
+ _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(float _pos_x = 0.0f, float _pos_y = 0.0f, float _pos_z = 0.0f) {
+ DXMatrixOrthoLH(mtx_projection, 1.0f * _pos_z, 1.0f / Width() * Height() * _pos_z, -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;
+ }
+
+ /**
+ * 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.
+ */
+ 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;
+};
diff --git a/3D/Devices/MTDX/MTDXDevice.h b/3D/Devices/MTDX/MTDXDevice.h
new file mode 100644
index 000000000..7bb1c93b8
--- /dev/null
+++ b/3D/Devices/MTDX/MTDXDevice.h
@@ -0,0 +1,157 @@
+//+------------------------------------------------------------------+
+//| 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 {
+ public:
+ /**
+ * 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;
+ }
+
+ /**
+ * Deinitializes graphics device.
+ */
+ bool Deinit() {
+ DXRelease(context);
+ 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.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);
+#ifdef __debug__
+ Print("DXContextClearColors: LastError: ", GetLastError());
+#endif
+ } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) {
+ DXContextClearDepth(context);
+#ifdef __debug__
+ Print("DXContextClearDepth: LastError: ", GetLastError());
+#endif
+ }
+ }
+
+ /**
+ * 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 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 RenderBuffers(VertexBuffer* _vertices, IndexBuffer* _indices = NULL) {
+ DXPrimiveTopologySet(context, DX_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ _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
+ }
+ }
+};
diff --git a/3D/Devices/MTDX/MTDXIndexBuffer.h b/3D/Devices/MTDX/MTDXIndexBuffer.h
new file mode 100644
index 000000000..6662aacab
--- /dev/null
+++ b/3D/Devices/MTDX/MTDXIndexBuffer.h
@@ -0,0 +1,69 @@
+//+------------------------------------------------------------------+
+//| 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:
+ MTDXIndexBuffer(Device* _device) : IndexBuffer(_device) {}
+
+ protected:
+ int handle;
+
+ /**
+ * Creates index buffer.
+ */
+ virtual bool Create(void*& _data[]) {
+ // handle = DXBufferCreate(Device().Context(), DX_BUFFER_INDEX, &_data);
+ return handle != INVALID_HANDLE;
+ }
+
+ /**
+ * Destructor;
+ */
+ ~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.
+ */
+ virtual void Select() {
+#ifdef __debug__
+ Print("Selecting indices ", handle);
+#endif
+ DXBufferSet(GetDevice().Context(), handle);
+#ifdef __debug__
+ Print("Select: LastError: ", GetLastError());
+#endif
+ }
+};
diff --git a/3D/Devices/MTDX/MTDXShader.h b/3D/Devices/MTDX/MTDXShader.h
new file mode 100644
index 000000000..c3dad254a
--- /dev/null
+++ b/3D/Devices/MTDX/MTDXShader.h
@@ -0,0 +1,201 @@
+//+------------------------------------------------------------------+
+//| 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 MVP's C-Buffer handle (register b0).
+ int cbuffer_mvp_handle;
+
+ MVPBuffer mvp_buffer;
+
+ // DX C-Buffer handle. (register b1).
+ int cbuffer_handle;
+
+ public:
+ /**
+ * Constructor.
+ */
+ MTDXShader(Device* _device) : Shader(_device) {}
+
+ /**
+ * Destructor.
+ */
+ ~MTDXShader() {
+ DXRelease(cbuffer_handle);
+ DXRelease(cbuffer_mvp_handle);
+ DXRelease(handle);
+ }
+
+ /**
+ * 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);
+
+#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;
+ }
+
+ /**
+ * Sets vertex/pixel data layout to be used by shader.
+ */
+ virtual void SetDataLayout(const ShaderVertexLayout& _layout[]) {
+ // Converting generic layout into MT5 DX's one.
+
+ DXVertexLayout _target_layout[];
+ ArrayResize(_target_layout, ArraySize(_layout));
+
+#ifdef __debug__
+ Print("ArrayResize: LastError: ", GetLastError());
+#endif
+
+ 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]);
+ }
+
+#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();
+ }
+
+#ifdef __MQL5__
+ /**
+ * 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;
+ default:
+ Alert("Too many components in vertex layout!");
+ }
+ }
+
+ Alert("Wrong vertex layout!");
+ return (ENUM_DX_FORMAT)0;
+ }
+#endif
+
+ /**
+ * Sets custom input buffer for shader.
+ */
+ template
+ 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 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];
+ _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);
+ }
+
+#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
new file mode 100644
index 000000000..e96b9c7b7
--- /dev/null
+++ b/3D/Devices/MTDX/MTDXVertexBuffer.h
@@ -0,0 +1,63 @@
+//+------------------------------------------------------------------+
+//| 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() {
+ // DXRelease(handle);
+ }
+
+ public:
+ /**
+ * Creates vertex buffer.
+ */
+ 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
+ }
+};
diff --git a/3D/Face.h b/3D/Face.h
new file mode 100644
index 000000000..558c0bc4e
--- /dev/null
+++ b/3D/Face.h
@@ -0,0 +1,96 @@
+//+------------------------------------------------------------------+
+//| 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; }
+
+ /**
+ * 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.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;
+ }
+
+ /**
+ * 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.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);
+
+ for (int i = 0; i < 4; ++i) {
+ points[i].Normal = _normal;
+ }
+ }
+};
diff --git a/3D/Frontend.h b/3D/Frontend.h
new file mode 100644
index 000000000..8080c65d4
--- /dev/null
+++ b/3D/Frontend.h
@@ -0,0 +1,112 @@
+//+------------------------------------------------------------------+
+//| 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"
+
+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.
+ */
+ bool Start() { return Init(); }
+
+ /**
+ * Deinitializes canvas.
+ */
+ bool End() { return Deinit(); }
+
+ /**
+ * Initializes canvas.
+ */
+ virtual bool Init() = NULL;
+
+ /**
+ * Deinitializes canvas.
+ */
+ virtual bool Deinit() = NULL;
+
+ /**
+ * Executed before render starts.
+ */
+ virtual void RenderBegin(int context) = NULL;
+
+ /**
+ * Executed after render ends.
+ */
+ virtual void RenderEnd(int context) = NULL;
+
+ /**
+ * Returns canvas' width.
+ */
+ virtual int Width() = NULL;
+
+ /**
+ * 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) {}
+};
diff --git a/3D/Frontends/MT5Frontend.h b/3D/Frontends/MT5Frontend.h
new file mode 100644
index 000000000..9bcec9e73
--- /dev/null
+++ b/3D/Frontends/MT5Frontend.h
@@ -0,0 +1,173 @@
+//+------------------------------------------------------------------+
+//| 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:
+ /**
+ * Initializes canvas.
+ */
+ virtual bool Init() {
+ // Hiding 2D chart.
+ ChartSetInteger(0, CHART_SHOW, false);
+ ChartRedraw();
+
+#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);
+#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;
+ }
+
+ /**
+ * Deinitializes canvas.
+ */
+ virtual bool Deinit() {
+ ResourceFree(resname);
+ ObjectDelete(0, objname);
+ ChartSetInteger(0, CHART_SHOW, true);
+ ChartRedraw();
+ return true;
+ }
+
+ /**
+ * Resizes target image buffer if needed.
+ */
+ bool Resize() {
+ if (Width() == last_width && Height() == last_height) {
+ return false;
+ }
+
+ 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();
+
+ return true;
+ }
+
+ /**
+ * 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);
+ ProcessDrawText();
+#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(1);
+ }
+
+ /**
+ * 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); }
+
+ /**
+ * 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
+ }
+};
diff --git a/3D/IndexBuffer.h b/3D/IndexBuffer.h
new file mode 100644
index 000000000..fdd83d91e
--- /dev/null
+++ b/3D/IndexBuffer.h
@@ -0,0 +1,63 @@
+//+------------------------------------------------------------------+
+//| 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;
+
+/**
+ * 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;
+
+ /**
+ * Fills index buffer with indices.
+ */
+ virtual void Fill(unsigned int& _indices[]) = NULL;
+
+ /**
+ * Activates index buffer for rendering.
+ */
+ virtual void Select() = NULL;
+};
diff --git a/3D/Interface.h b/3D/Interface.h
new file mode 100644
index 000000000..87015f3a4
--- /dev/null
+++ b/3D/Interface.h
@@ -0,0 +1,131 @@
+//+------------------------------------------------------------------+
+//| 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;
+};
+
+#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;
+ 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);
+ }
+}
+#endif
+
+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;
+
+#ifdef __MQL5__
+ 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; }
+#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/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/Math.h b/3D/Math.h
new file mode 100644
index 000000000..e631a214a
--- /dev/null
+++ b/3D/Math.h
@@ -0,0 +1,3225 @@
+//+------------------------------------------------------------------+
+//| 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;
+ }
+ 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 |
+//+------------------------------------------------------------------+
+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;
+ }
+
+#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);
+ 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;
+ }
+#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);
+ 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..0ee82c0dc
--- /dev/null
+++ b/3D/Mesh.h
@@ -0,0 +1,256 @@
+//+------------------------------------------------------------------+
+//| 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 "Material.h"
+#include "Math.h"
+#include "TSR.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.x, _point.Position.y, _point.Position.z);
+ }
+
+ bool operator==(const PointEntry& _r) {
+ return key == MakeKey(_r.point.Position.x, _r.point.Position.y, _r.point.Position.z);
+ }
+
+ 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);
+ }
+};
+
+// Mesh points type.
+enum ENUM_MESH_TYPE { MESH_TYPE_CONNECTED_POINTS, MESH_TYPE_SEPARATE_POINTS };
+
+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;
+ Material material;
+
+ public:
+ /**
+ * Constructor.
+ */
+ Mesh(ENUM_MESH_TYPE _type = MESH_TYPE_SEPARATE_POINTS) {
+ type = _type;
+ initialized = false;
+ }
+
+ /**
+ * Initializes graphics device-related things.
+ */
+ virtual void Initialize(Device* _device) {}
+
+ TSR* GetTSR() { return &tsr; }
+
+ void SetTSR(const TSR& _tsr) { tsr = _tsr; }
+
+ /**
+ * Adds a single 3 or 4-vertex face.
+ */
+ void AddFace(Face& face) {
+ face.UpdateNormal();
+ 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.
+ */
+ 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;
+ }
+
+#ifdef __debug__
+ Print("Getting buffers. Mesh type = ", EnumToString(type));
+#endif
+ 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] = type == MESH_TYPE_SEPARATE_POINTS ? -1 : _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) {
+ 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);
+ }
+ }
+ }
+
+ 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.x) + ", " +
+ DoubleToString(_vertices[i].Position.y) + "," + DoubleToString(_vertices[i].Position.z) + " | ";
+ _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 += ", ";
+ }
+ }
+
+ _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 += "]";
+
+#ifdef __debug__
+ Print("Vertices: ", _s_vertices);
+ Print("Indices: ", _s_indices);
+#endif
+
+ vbuff = _vbuff = _device.VertexBuffer(_vertices);
+ ibuff = _ibuff = _device.IndexBuffer(_indices);
+ return true;
+ }
+};
diff --git a/3D/Shader.h b/3D/Shader.h
new file mode 100644
index 000000000..51ae50504
--- /dev/null
+++ b/3D/Shader.h
@@ -0,0 +1,108 @@
+//+------------------------------------------------------------------+
+//| 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,
+};
+
+class Device;
+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:
+ float _unused1;
+
+ public:
+ DXColor mat_color;
+
+ private:
+ // char _unused2[1];
+};
+
+// Vertex layout used for Vertex Shaders.
+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 {
+ // Reference to graphics device.
+ WeakRef device;
+
+ public:
+ /**
+ * Constructor.
+ */
+ Shader(Device* _device) { device = _device; }
+
+ /**
+ * Returns base graphics device.
+ */
+ Device* GetDevice() { return device.Ptr(); }
+
+ /**
+ * 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.
+#ifdef __debug__
+ Print("Setting CBuffer data for MT5");
+#endif
+ ((MTDXShader*)&this).SetCBuffer(data);
+ } else {
+ Alert("Unsupported cbuffer device target");
+ }
+ }
+
+ /**
+ * Selectes shader to be used by graphics device for rendering.
+ */
+ virtual void Select() = NULL;
+};
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/Shaders/cube_ps.hlsl b/3D/Shaders/cube_ps.hlsl
new file mode 100644
index 000000000..6218a4748
--- /dev/null
+++ b/3D/Shaders/cube_ps.hlsl
@@ -0,0 +1,17 @@
+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.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
new file mode 100644
index 000000000..d9c651d7d
--- /dev/null
+++ b/3D/Shaders/cube_vs.hlsl
@@ -0,0 +1,33 @@
+cbuffer MVP : register(b0) {
+ matrix world;
+ matrix view;
+ matrix projection;
+ float3 lightdir;
+ float4 mat_color;
+};
+
+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;
+
+ matrix mvp = mul(mul(view, world), projection);
+ output.position = mul(input.position, mvp);
+
+ output.normal = normalize(mul(input.normal, world));
+ output.lightdir = lightdir;
+ output.color = input.color * mat_color;
+
+ return output;
+}
diff --git a/3D/TSR.h b/3D/TSR.h
new file mode 100644
index 000000000..ee015a01f
--- /dev/null
+++ b/3D/TSR.h
@@ -0,0 +1,62 @@
+//+------------------------------------------------------------------+
+//| 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"
+
+class TSR {
+ public:
+ 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_scale);
+ DXMatrixMultiply(_mtx_result, _mtx_result, _mtx_translation);
+
+ return _mtx_result;
+ }
+};
diff --git a/3D/Vertex.h b/3D/Vertex.h
new file mode 100644
index 000000000..8466fa312
--- /dev/null
+++ b/3D/Vertex.h
@@ -0,0 +1,24 @@
+#include "../Refs.mqh"
+
+/**
+ * Generic vertex to be used by meshes.
+ */
+struct Vertex {
+ DXVector3 Position;
+ DXVector3 Normal;
+ DXColor Color;
+
+ Vertex() {
+ Color.r = 1.0f;
+ Color.g = 1.0f;
+ Color.b = 1.0f;
+ Color.a = 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/3D/VertexBuffer.h b/3D/VertexBuffer.h
new file mode 100644
index 000000000..822c33fb2
--- /dev/null
+++ b/3D/VertexBuffer.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
+ * Generic graphics vertex buffer.
+ */
+
+#include "../Refs.mqh"
+
+class VertexBuffer : 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;
+};
diff --git a/Action.mqh b/Action.mqh
deleted file mode 100644
index 5ed379560..000000000
--- a/Action.mqh
+++ /dev/null
@@ -1,373 +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
- * Provides integration with actions.
- */
-
-// Prevents processing this includes file for the second time.
-#ifndef ACTION_MQH
-#define ACTION_MQH
-
-// Forward class declaration.
-class Action;
-
-// Includes.
-#include "Action.enum.h"
-#include "Action.struct.h"
-#include "Condition.enum.h"
-#include "EA.mqh"
-
-/**
- * Action class.
- */
-class Action {
- public:
- protected:
- // Class variables.
- Ref logger;
-
- public:
- // Class variables.
- 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);
- actions.Push(_entry);
- }
- template
- Action(T _action_id, void *_obj = NULL) {
- ActionEntry _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);
- _entry.SetArgs(_args);
- if (_obj != NULL) {
- _entry.SetObject(_obj);
- }
- actions.Push(_entry);
- }
-
- /**
- * Class copy constructor.
- */
- Action(Action &_cond) { actions = _cond.GetActions(); }
-
- /* Main methods */
-
- /**
- * Execute actions.
- */
- bool Execute() {
- bool _result = true, _executed = false;
- for (DictStructIterator iter = actions.Begin(); iter.IsValid(); ++iter) {
- bool _curr_result = false;
- ActionEntry _entry = iter.Value();
- if (!_entry.IsValid()) {
- // Ignore invalid entries.
- continue;
- }
- if (_entry.IsActive()) {
- _executed = _result &= Execute(_entry);
- }
- }
- return _result && _executed;
- }
-
- /**
- * Execute specific action.
- */
- static bool Execute(ActionEntry &_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);
- } 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 = ((IndicatorBase *)_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
- }
- if (_result) {
- _entry.AddFlags(ACTION_ENTRY_FLAG_IS_DONE);
- _entry.RemoveFlags(ACTION_ENTRY_FLAG_IS_ACTIVE);
- _entry.last_success = TimeCurrent();
- } else {
- if (--_entry.tries <= 0) {
- _entry.AddFlags(ACTION_ENTRY_FLAG_IS_INVALID);
- _entry.RemoveFlags(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.
- */
- 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();
- if (_entry.HasFlag(_flag)) {
- _counter++;
- }
- }
- return _counter;
- }
-
- /* Setters */
-
- /**
- * Sets entry flags.
- */
- 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();
- 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;
- }
-
- /* Conditions and actions */
-
- /**
- * Checks for Task condition.
- *
- * @param ENUM_ACTION_CONDITION _cond
- * Action condition.
- * @return
- * Returns true when the condition is met.
- */
- 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 Action condition: %s!", EnumToString(_cond), __FUNCTION_LINE__));
- return false;
- }
- }
- bool CheckCondition(ENUM_ACTION_CONDITION _cond) {
- ARRAY(DataParamEntry, _args);
- return Action::CheckCondition(_cond, _args);
- }
-
- /**
- * Execute action of action.
- *
- * @param ENUM_ACTION_ACTION _action
- * Action of action to execute.
- * @return
- * Returns true when the action has been executed successfully.
- */
- 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 Action::ExecuteAction(_action, _args);
- }
-
- /* Other methods */
-};
-
-#endif // ACTION_MQH
diff --git a/Action.struct.h b/Action.struct.h
deleted file mode 100644
index 1f5481f14..000000000
--- a/Action.struct.h
+++ /dev/null
@@ -1,120 +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 Action'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 "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.enum.h"
-#include "Trade.enum.h"
-
-/* Entry for Action class. */
-struct ActionEntry {
- unsigned char flags; /* Action flags. */
- datetime last_success; /* Time of the previous check. */
- int frequency; /* How often to check. */
- long action_id; /* Action ID. */
- short tries; /* Number of retries left. */
- void *obj; /* Reference to associated object. */
- ENUM_ACTION_TYPE type; /* Action type. */
- DataParamEntry args[]; /* Action 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(); }
- // Deconstructor.
- ~ActionEntry() {
- // 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_ACTION_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(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(); }
- // Getters.
- long GetId() { return action_id; }
- ENUM_ACTION_TYPE GetType() { return type; }
- // Setter methods.
- 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; }
-
- 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.PassArray(this, "args", args);
- return SerializerNodeObject;
- }
-
- SERIALIZER_EMPTY_STUB;
-};
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/Chart.struct.static.h b/Chart.struct.static.h
index 0c728bcc4..f892cf2a8 100644
--- a/Chart.struct.static.h
+++ b/Chart.struct.static.h
@@ -186,15 +186,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/Condition.mqh b/Condition.mqh
deleted file mode 100644
index 915cbcd4e..000000000
--- a/Condition.mqh
+++ /dev/null
@@ -1,267 +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
- * Provides integration with conditions.
- */
-
-// Prevents processing this includes file for the second time.
-#ifndef CONDITION_MQH
-#define 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"
-
-// Includes class enum and structs.
-#include "Condition.enum.h"
-#include "Condition.struct.h"
-
-/**
- * Condition class.
- */
-class Condition {
- public:
- protected:
- // Class variables.
- Ref logger;
-
- public:
- // Class variables.
- 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);
- conds.Push(_entry);
- }
- template
- Condition(T _cond_id, void *_obj = NULL) {
- ConditionEntry _entry(_cond_id);
- if (_obj != NULL) {
- _entry.SetObject(_obj);
- }
- conds.Push(_entry);
- }
- template
- Condition(T _cond_id, MqlParam &_args[], void *_obj = NULL) {
- Init();
- ConditionEntry _entry(_cond_id);
- _entry.SetArgs(_args);
- if (_obj != NULL) {
- _entry.SetObject(_obj);
- }
- conds.Push(_entry);
- }
-
- /**
- * Class copy constructor.
- */
- Condition(Condition &_cond) { conds = _cond.GetConditions(); }
-
- /* Main methods */
-
- /**
- * Test conditions.
- */
- bool Test() {
- bool _result = false, _prev_result = true;
- for (DictStructIterator iter = conds.Begin(); iter.IsValid(); ++iter) {
- bool _curr_result = false;
- ConditionEntry _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;
- }
-
- /**
- * Test specific condition.
- */
- static bool Test(ConditionEntry &_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
- }
- if (_result) {
- _entry.last_success = TimeCurrent();
- _entry.tries--;
- }
- _entry.last_check = TimeCurrent();
- return _result;
- }
-
- /* Other methods */
-
- /* Getters */
-
- /**
- * Returns conditions.
- */
- DictStruct *GetConditions() { return &conds; }
-
- /* Setters */
-};
-#endif // CONDITION_MQH
diff --git a/Condition.struct.h b/Condition.struct.h
deleted file mode 100644
index 6e3376812..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.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/Dict.mqh b/Dict.mqh
index c5275b985..cd55d66ba 100644
--- a/Dict.mqh
+++ b/Dict.mqh
@@ -173,6 +173,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;
+ }
+
/**
* Checks whether dictionary contains given value.
*/
@@ -191,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 3585c1972..8bcc9d412 100644
--- a/DictObject.mqh
+++ b/DictObject.mqh
@@ -173,29 +173,49 @@ class DictObject : public DictBase {
return slot.value == value;
}
- protected:
/**
- * Inserts value into given array of DictSlots.
+ * Returns index of dictionary's value or -1 if value doesn't exist.
*/
- 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;
+ 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.
+ */
+ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) {
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 b2cd3d5c9..b4cb0d747 100644
--- a/DictStruct.mqh
+++ b/DictStruct.mqh
@@ -233,18 +233,25 @@ class DictStruct : public DictBase {
return slot.value == value;
}
- protected:
/**
- * Inserts value into given array of DictSlots.
+ * Returns index of dictionary's value or -1 if value doesn't exist.
*/
- 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;
+ 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.
+ */
+ bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) {
if (_mode == DictModeUnknown)
_mode = DictModeDict;
else if (_mode != DictModeDict) {
@@ -255,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) {
diff --git a/EA.mqh b/EA.mqh
index f499717d7..080e78c38 100644
--- a/EA.mqh
+++ b/EA.mqh
@@ -30,9 +30,7 @@
#define EA_MQH
// Includes.
-#include "Action.enum.h"
#include "Chart.mqh"
-#include "Condition.enum.h"
#include "Data.struct.h"
#include "Dict.mqh"
#include "DictObject.mqh"
@@ -46,13 +44,14 @@
#include "SerializerSqlite.mqh"
#include "Strategy.mqh"
#include "SummaryReport.mqh"
-#include "Task.mqh"
+#include "Task/TaskManager.h"
+#include "Task/Taskable.h"
#include "Terminal.mqh"
#include "Trade.mqh"
#include "Trade/TradeSignal.h"
#include "Trade/TradeSignalManager.h"
-class EA {
+class EA : public Taskable {
protected:
// Class variables.
Account *account;
@@ -68,24 +67,41 @@ class EA {
DictObject trade;
DictObject> data_indi;
DictObject> data_stg;
- DictStruct tasks;
EAParams eparams;
EAProcessResult eresults;
EAState estate;
+ 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)),
+ 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);
+ }
+
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.
- TaskAdd(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;
@@ -375,8 +391,6 @@ class EA {
}
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);
@@ -658,53 +672,6 @@ class EA {
}
*/
- /* Tasks */
-
- /**
- * Add task.
- */
- bool TaskAdd(TaskEntry &_entry) {
- bool _result = false;
- if (_entry.IsValid()) {
- switch (_entry.GetConditionType()) {
- 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.GetActionType()) {
- 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 */
/**
@@ -865,24 +832,39 @@ class EA {
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;
}
- /* Conditions and actions */
+ /* Tasks methods */
/**
- * Checks for EA condition.
- *
- * @param ENUM_EA_CONDITION _cond
- * EA condition.
- * @return
- * Returns true when the condition is met.
+ * Add task.
*/
- bool CheckCondition(ENUM_EA_CONDITION _cond, DataParamEntry &_args[]) {
- switch (_cond) {
+ 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.
+ */
+ 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:
@@ -907,27 +889,31 @@ class EA {
case EA_COND_ON_QUIT:
return estate.IsOnQuit();
default:
- logger.Error(StringFormat("Invalid EA condition: %s!", EnumToString(_cond), __FUNCTION_LINE__));
- return false;
+ GetLogger().Error(StringFormat("Invalid EA condition: %d!", _entry.GetId(), __FUNCTION_LINE__));
+ SetUserError(ERR_INVALID_PARAMETER);
+ break;
}
+ return _result;
}
- bool CheckCondition(ENUM_EA_CONDITION _cond) {
- ARRAY(DataParamEntry, _args);
- return EA::CheckCondition(_cond, _args);
+
+ /**
+ * Gets a copy of structure.
+ */
+ virtual DataParamEntry Get(const TaskGetterEntry &_entry) {
+ DataParamEntry _result;
+ switch (_entry.GetId()) {
+ default:
+ break;
+ }
+ return _result;
}
/**
- * Execute EA action.
- *
- * @param ENUM_EA_ACTION _action
- * EA action to execute.
- * @return
- * Returns true when the action has been executed successfully.
+ * Runs an action.
*/
- bool ExecuteAction(ENUM_EA_ACTION _action, DataParamEntry &_args[]) {
- bool _result = true;
- long arg_size = ArraySize(_args);
- switch (_action) {
+ virtual bool Run(const TaskActionEntry &_entry) {
+ bool _result = false;
+ switch (_entry.GetId()) {
case EA_ACTION_DISABLE:
estate.Enable(false);
return true;
@@ -937,46 +923,42 @@ class EA {
case EA_ACTION_EXPORT_DATA:
DataExport();
return true;
- case EA_ACTION_STRATS_EXE_ACTION:
+ 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) {
- 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);
+
+ _result &= _strat.Run(_entry_strat);
}
return _result;
+ }
case EA_ACTION_TASKS_CLEAN:
// @todo
- return tasks.Size() == 0;
- default:
- logger.Error(StringFormat("Invalid EA action: %s!", EnumToString(_action), __FUNCTION_LINE__));
+ // return tasks.Size() == 0;
+ SetUserError(ERR_INVALID_PARAMETER);
return false;
+ default:
+ GetLogger().Error(StringFormat("Invalid EA action: %d!", _entry.GetId(), __FUNCTION_LINE__));
+ SetUserError(ERR_INVALID_PARAMETER);
}
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);
+
+ /**
+ * 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 */
diff --git a/EA.struct.h b/EA.struct.h
index dbbe64063..5bed4845d 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 {
@@ -225,7 +225,7 @@ struct EAState {
public: // @todo: Move to protected.
DateTime last_updated; // Last updated.
protected:
- unsigned int flags; // Action flags.
+ unsigned int flags; // TaskAction flags.
unsigned int new_periods; // Started periods.
public:
/* Struct's enumerations */
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/Indicator.enum.h b/Indicator.enum.h
index 1587ce083..375064b34 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
@@ -218,12 +219,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 065234ef9..53103b7cf 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 */
@@ -77,7 +100,8 @@ class Indicator : public IndicatorBase {
/**
* Class constructor.
*/
- Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) : IndicatorBase(_indi_src) {
+ Indicator(const TS& _iparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0)
+ : IndicatorBase(_iparams.GetTf(), NULL) {
iparams = _iparams;
SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype));
if (_indi_src != NULL) {
@@ -85,7 +109,13 @@ class Indicator : public IndicatorBase {
}
Init();
}
- Indicator(ENUM_INDICATOR_TYPE _itype, int _shift = 0, string _name = "") {
+ Indicator(const TS& _iparams, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorBase(_tf) {
+ iparams = _iparams;
+ SetName(_iparams.name != "" ? _iparams.name : EnumToString(iparams.itype));
+ Init();
+ }
+ Indicator(ENUM_INDICATOR_TYPE _itype, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, int _shift = 0, string _name = "")
+ : IndicatorBase(_tf) {
iparams.SetIndicatorType(_itype);
iparams.SetShift(_shift);
SetName(_name != "" ? _name : EnumToString(iparams.itype));
@@ -97,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.
*/
@@ -155,8 +163,10 @@ class Indicator : public IndicatorBase {
* Gets an indicator property flag.
*/
bool GetFlag(INDICATOR_ENTRY_FLAGS _prop, datetime _bar_time) {
- IndicatorDataEntry _entry = GetEntry(_bar_time);
- return _entry.CheckFlag(_prop);
+ // @fixme
+ // IndicatorDataEntry _entry = GetEntry(_bar_time);
+ // return _entry.CheckFlag(_prop);
+ return false;
}
/* Buffer methods */
@@ -881,15 +891,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;
}
@@ -910,15 +937,44 @@ class Indicator : public IndicatorBase {
* @return
* Returns IndicatorDataEntry struct filled with indicator values.
*/
- virtual IndicatorDataEntry GetEntry(datetime _bar_time = 0) {
- IndicatorDataEntry _entry = idata.GetByKey(_bar_time);
+ virtual IndicatorDataEntry GetEntry(int _shift = -1) {
+ ResetLastError();
+ int _ishift = _shift >= 0 ? _shift : iparams.GetShift();
+ long _bar_time = 0; // GetBarTime(_ishift); // @fixme
+ IndicatorDataEntry _entry; // = idata.GetByKey(_bar_time); // @fixme
if (_bar_time > 0 && !_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) {
_entry.Resize(iparams.GetMaxModes());
_entry.timestamp = _bar_time;
for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) {
- // _entry.values[_mode] = GetValue(_mode, _ishift); // @todo
+ 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;
+ }
}
- GetEntryAlter(_entry, _bar_time);
+ GetEntryAlter(_entry, _ishift);
_entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry));
if (_entry.IsValid()) {
idata.Add(_entry, _bar_time);
@@ -941,40 +997,9 @@ class Indicator : public IndicatorBase {
* This method allows user to modify the struct entry before it's added to cache.
* This method is called on GetEntry() right after values are set.
*/
- virtual void GetEntryAlter(IndicatorDataEntry& _entry, datetime _bar_time = 0) {
- _entry.AddFlags(_entry.GetDataTypeFlag(iparams.GetDataValueType()));
+ virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) {
+ _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 DataParamEntry GetEntryValue(datetime _bar_time = 0, int _mode = 0) {
- IndicatorDataEntry _entry = GetEntry(_bar_time);
- 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);
- }
- 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
diff --git a/Indicator.struct.h b/Indicator.struct.h
index b84968357..8891b8871 100644
--- a/Indicator.struct.h
+++ b/Indicator.struct.h
@@ -45,109 +45,149 @@ 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(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) {
+ 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,30 +328,35 @@ 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_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;
- }
- return TYPE_DOUBLE;
- }
- INDICATOR_ENTRY_FLAGS GetDataTypeFlag(ENUM_DATATYPE _dt) {
+ ENUM_DATATYPE GetDataType(int _mode) { return values[_mode].GetDataType(); }
+ 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; }
@@ -334,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() {
@@ -471,7 +521,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..98e262c60 100644
--- a/Indicator.struct.serialize.h
+++ b/Indicator.struct.serialize.h
@@ -40,43 +40,59 @@ 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 (values[i].GetDataType()) {
+ case TYPE_DOUBLE:
+ _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].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].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].value.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].value.vlong,
+ SERIALIZER_FIELD_FLAG_DYNAMIC | SERIALIZER_FIELD_FLAG_FEATURE);
}
- */
- }
+ break;
+ default:
+ SetUserError(ERR_INVALID_PARAMETER);
+ break;
}
}
return SerializerNodeObject;
}
/* 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 df0cb4388..6361d3a8b 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"
@@ -80,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
/**
@@ -118,7 +128,36 @@ class IndicatorBase : public Object {
/**
* Class constructor.
*/
- IndicatorBase(IndicatorBase* _indi_src = NULL) : indi_src(_indi_src), is_fed(false) {}
+ IndicatorBase() : indi_src(NULL) {
+ calc_start_bar = 0;
+ is_fed = false;
+ }
+
+ /**
+ * Class constructor.
+ */
+ IndicatorBase(ChartParams& _cparams) : indi_src(NULL) {
+ calc_start_bar = 0;
+ is_fed = false;
+ }
+
+ /**
+ * Class constructor.
+ */
+ IndicatorBase(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _symbol = NULL) {
+ calc_start_bar = 0;
+ is_fed = false;
+ indi_src = NULL;
+ }
+
+ /**
+ * Class constructor.
+ */
+ IndicatorBase(ENUM_TIMEFRAMES_INDEX _tfi, string _symbol = NULL) {
+ calc_start_bar = 0;
+ is_fed = false;
+ indi_src = NULL;
+ }
/**
* Class deconstructor.
@@ -813,16 +852,11 @@ class IndicatorBase : public Object {
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;
+ GetEntryValue(_shift, _mode).Get(_out);
+ return _out;
}
/**
@@ -914,7 +948,7 @@ class IndicatorBase : public Object {
/**
* Returns the indicator's entry value.
*/
- virtual DataParamEntry GetEntryValue(datetime _bar_time = 0, int _mode = 0) = NULL;
+ virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = -1) = NULL;
/**
* Returns indicator value for a given shift and mode.
@@ -958,7 +992,6 @@ class IndicatorBase : public Object {
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);
}
@@ -967,23 +1000,24 @@ class IndicatorBase : public Object {
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/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh
index d1bc29ff2..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 double GetValue(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 33000b0d4..f9e014ec0 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,15 +57,16 @@ class Indi_Pattern : public Indicator {
/**
* Returns the indicator's value.
*/
- virtual double GetValue(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 96befe0cf..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;
@@ -100,15 +105,16 @@ 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 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(_Symbol, GetTf(), _shift, THIS_PTR);
+ _value = Indi_AC::iAC(GetSymbol(), GetTf(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 aaa0c8658..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 double GetValue(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(_Symbol, GetTf(), _shift, THIS_PTR);
+ _value = Indi_AD::iAD(GetSymbol(), GetTf(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 d02d11225..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 double GetValue(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(_Symbol, 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, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
- _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
+ _mode, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
+ break;
}
return _value;
}
diff --git a/Indicators/Indi_ADXW.mqh b/Indicators/Indi_ADXW.mqh
index 0a4be9716..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 double GetValue(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(_Symbol, 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, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
- _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
+ _mode, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_AMA.mqh b/Indicators/Indi_AMA.mqh
index 0e48422d2..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 double GetValue(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(_Symbol, GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(), GetAMAShift(),
- GetAppliedPrice() /*]*/, _mode, _shift, THIS_PTR);
+ _value = Indi_AMA::iAMA(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetFastPeriod(), GetSlowPeriod(),
+ GetAMAShift(), GetAppliedPrice() /*]*/, _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(),
- GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(),
+ GetFastPeriod(), GetSlowPeriod(), GetAMAShift() /*]*/, _mode, _ishift);
break;
case IDATA_INDICATOR:
diff --git a/Indicators/Indi_AO.mqh b/Indicators/Indi_AO.mqh
index cbda37d66..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 double GetValue(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(_Symbol, GetTf(), _shift, _mode, THIS_PTR);
+ _value = Indi_AO::iAO(GetSymbol(), GetTf(), _ishift, _mode, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 b15a0505b..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 double GetValue(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, _Symbol, GetTf(), iparams.GetCustomIndicatorName(),
- /*[*/ GetMaximumPriceChanging() /*]*/, 0, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(),
+ /*[*/ GetMaximumPriceChanging() /*]*/, 0, _ishift);
break;
case IDATA_ONCALCULATE: {
- INDICATOR_CALCULATE_POPULATE_PARAMS_AND_CACHE_LONG(_Symbol, GetTf(),
+ 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 304edb113..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 double GetValue(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(_Symbol, GetTf(), GetPeriod(), _shift, THIS_PTR);
+ _value = Indi_ATR::iATR(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 22fe7b7de..3cef8086f 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 double GetValue(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 GetValue((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(_Symbol, 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, _Symbol, 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 4d6d1e443..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 double GetValue(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 4b0318366..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 double GetValue(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(_Symbol, 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, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/,
- _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ VOLUME_TICK /*]*/,
+ _mode, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
@@ -140,7 +141,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_BWZT.mqh b/Indicators/Indi_BWZT.mqh
index cbfed6264..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 double GetValue(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(_Symbol, GetTf(), _mode, _shift, THIS_PTR);
+ _value = Indi_BWZT::iBWZT(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 6e15f6d9e..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 double GetValue(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(_Symbol, GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(), GetAppliedPrice(),
- (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR);
+ _value = Indi_Bands::iBands(GetSymbol(), GetTf(), GetPeriod(), GetDeviation(), GetBandsShift(),
+ GetAppliedPrice(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(),
- GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(),
+ GetBandsShift(), GetDeviation(), GetAppliedPrice() /* ] */, _mode, _ishift);
break;
case IDATA_INDICATOR:
// Calculating bands value from specified indicator.
- _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), _Symbol, GetTf(), GetPeriod(), GetDeviation(),
- GetBandsShift(), (ENUM_BANDS_LINE)_mode, _shift, THIS_PTR);
+ _value = Indi_Bands::iBandsOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDeviation(),
+ GetBandsShift(), (ENUM_BANDS_LINE)_mode, _ishift, THIS_PTR);
break;
}
return _value;
diff --git a/Indicators/Indi_BearsPower.mqh b/Indicators/Indi_BearsPower.mqh
index 57eae631e..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 double GetValue(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(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR);
+ _value = _value = iBearsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
- _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
+ _mode, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_BullsPower.mqh b/Indicators/Indi_BullsPower.mqh
index 79244878d..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 double GetValue(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(_Symbol, GetTf(), GetPeriod(), GetAppliedPrice(), _shift, THIS_PTR);
+ _value = iBullsPower(GetSymbol(), GetTf(), GetPeriod(), GetAppliedPrice(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/,
- _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetPeriod() /**/,
+ _mode, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_CCI.mqh b/Indicators/Indi_CCI.mqh
index 721b034f9..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 double GetValue(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(_Symbol, 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, _Symbol, GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(),
- GetAppliedPrice() /* ] */, 0, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /* [ */ GetPeriod(),
+ GetAppliedPrice() /* ] */, 0, _ishift);
break;
case IDATA_INDICATOR:
ValidateSelectedDataSource();
// @fixit Somehow shift isn't used neither in MT4 nor MT5.
- _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), _Symbol, GetTf(), GetPeriod(), GetDataSourceMode(),
- _shift /* + iparams.shift*/);
+ _value = Indi_CCI::iCCIOnIndicator(GetDataSource(), GetSymbol(), GetTf(), GetPeriod(), GetDataSourceMode(),
+ _ishift /* + iparams.shift*/);
break;
}
return _value;
diff --git a/Indicators/Indi_CHO.mqh b/Indicators/Indi_CHO.mqh
index 4145f26cf..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 double GetValue(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(_Symbol, GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(),
- GetInputVolume() /*]*/, _mode, _shift, THIS_PTR);
+ _value = Indi_CHO::iChaikin(GetSymbol(), GetTf(), /*[*/ GetSlowMA(), GetFastMA(), GetSmoothMethod(),
+ GetInputVolume() /*]*/, _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(),
- GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetFastMA(),
+ GetSlowMA(), GetSmoothMethod(), GetInputVolume() /*]*/, 0, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_CHV.mqh b/Indicators/Indi_CHV.mqh
index d31127d65..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 double GetValue(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(_Symbol, GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/,
- _mode, _shift, THIS_PTR);
+ _value = Indi_CHV::iCHV(GetSymbol(), GetTf(), /*[*/ GetSmoothPeriod(), GetCHVPeriod(), GetSmoothMethod() /*]*/,
+ _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(),
- GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(),
+ GetCHVPeriod(), GetSmoothMethod() /*]*/, _mode, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_ColorBars.mqh b/Indicators/Indi_ColorBars.mqh
index f9a82dfa5..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 double GetValue(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(_Symbol, GetTf(), _mode, _shift, THIS_PTR);
+ _value = Indi_ColorBars::iColorBars(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 bfc44cefc..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 double GetValue(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(_Symbol, GetTf(), _mode, _shift, THIS_PTR);
+ _value = Indi_ColorCandlesDaily::iCCD(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 25b17781c..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 double GetValue(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(_Symbol, GetTf(), _mode, _shift, THIS_PTR);
+ _value = Indi_ColorLine::iColorLine(GetSymbol(), GetTf(), _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, 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 22aefae8b..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 double GetValue(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, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(),
- GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetSmoothPeriod(),
+ GetSmoothShift(), GetSmoothMethod() /*]*/, 0, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_DEMA.mqh b/Indicators/Indi_DEMA.mqh
index 291bf8bee..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 double GetValue(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(_Symbol, 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, _Symbol, GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(),
- GetAppliedPrice() /*]*/, _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.custom_indi_name, /*[*/ GetPeriod(), GetMAShift(),
+ 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 299687be0..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 double GetValue(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(_Symbol, GetTf(), GetPeriod(), _shift, THIS_PTR);
+ _value = _value = Indi_DeMarker::iDeMarker(GetSymbol(), GetTf(), GetPeriod(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0,
- _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
+ 0, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_Demo.mqh b/Indicators/Indi_Demo.mqh
index 9d36aa8c9..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 double GetValue(int _mode = 0, int _shift = 0) {
- double _value = Indi_Demo::iDemo(_Symbol, 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 4af92b96b..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 double GetValue(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(_Symbol, GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode, _shift,
- THIS_PTR);
+ _value = Indi_DetrendedPrice::iDPO(GetSymbol(), GetTf(), /*[*/ GetPeriod(), GetAppliedPrice() /*]*/, _mode,
+ _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/, 0,
- _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod() /*]*/,
+ 0, _ishift);
break;
default:
SetUserError(ERR_INVALID_PARAMETER);
diff --git a/Indicators/Indi_Drawer.mqh b/Indicators/Indi_Drawer.mqh
index 957b25106..9cf22635d 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 "Price/Indi_Price.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);
@@ -100,7 +98,8 @@ class Indi_Drawer : public Indicator {
virtual void OnTick() {
Indicator::OnTick();
- ActionEntry action(INDI_ACTION_SET_VALUE);
+ /* @fixme
+ TaskActionEntry action(INDI_ACTION_SET_VALUE);
ArrayResize(action.args, 3);
action.args[0].type = TYPE_LONG;
action.args[0].integer_value = GetBarTime();
@@ -110,9 +109,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");
@@ -127,7 +128,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__
@@ -137,6 +138,7 @@ class Indi_Drawer : public Indicator {
// Drawing on the buffer.
}
}
+ */
}
Redis *Redis() { return &redis; }
@@ -172,15 +174,16 @@ class Indi_Drawer : public Indicator {
/**
* Returns the indicator's value.
*/
- virtual double GetValue(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(_Symbol, GetTf(), _shift, THIS_PTR);
+ _value = Indi_Drawer::iDrawer(GetSymbol(), GetTf(), _ishift, THIS_PTR);
break;
case IDATA_INDICATOR:
- _value = Indi_Drawer::iDrawerOnIndicator(GetDataSource(), THIS_PTR, _Symbol, 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 7f81e699d..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 double GetValue(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(_Symbol, GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(),
- GetAppliedPrice(), GetDeviation(), _mode, _shift, THIS_PTR);
+ _value = Indi_Envelopes::iEnvelopes(GetSymbol(), GetTf(), GetMAPeriod(), GetMAMethod(), GetMAShift(),
+ GetAppliedPrice(), GetDeviation(), _mode, _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(),
- GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /**/ GetMAPeriod(),
+ GetMAMethod(), GetMAShift(), GetAppliedPrice(), GetDeviation() /**/, _mode, _ishift);
break;
case IDATA_INDICATOR:
- _value = Indi_Envelopes::iEnvelopesOnIndicator(GetCache(), GetDataSource(), _Symbol, GetTf(), GetMAPeriod(),
+ _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;
}
@@ -227,7 +229,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_Force.mqh b/Indicators/Indi_Force.mqh
index 24c6fd029..9e047338b 100644
--- a/Indicators/Indi_Force.mqh
+++ b/Indicators/Indi_Force.mqh
@@ -117,16 +117,18 @@ class Indi_Force : public Indicator {
/**
* Returns the indicator's value.
*/
- virtual double GetValue(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(_Symbol, GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _shift, THIS_PTR);
+ _value =
+ Indi_Force::iForce(GetSymbol(), GetTf(), GetPeriod(), GetMAMethod(), GetAppliedPrice(), _ishift, THIS_PTR);
break;
case IDATA_ICUSTOM:
- _value = iCustom(istate.handle, _Symbol, GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(),
- GetMAMethod(), GetAppliedPrice(), VOLUME_TICK /*]*/, 0, _shift);
+ _value = iCustom(istate.handle, GetSymbol(), GetTf(), iparams.GetCustomIndicatorName(), /*[*/ GetPeriod(),
+ 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 34074a17c..7640170c0 100644
--- a/Indicators/Indi_FractalAdaptiveMA.mqh
+++ b/Indicators/Indi_FractalAdaptiveMA.mqh
@@ -134,16 +134,17 @@ class Indi_FrAMA : public Indicator