Browse Source

first usable version

Nicolas Winkler 5 years ago
parent
commit
741098f331
18 changed files with 441 additions and 480 deletions
  1. 35 30
      Almond.cpp
  2. 6 4
      Almond.h
  3. 1 0
      Almond.pro
  4. 3 1
      Almond.qrc
  5. 65 27
      Almond.ui
  6. 35 214
      Gradient.cpp
  7. 5 1
      Gradient.h
  8. 41 11
      MandelWidget.cpp
  9. 35 17
      MandelWidget.h
  10. BIN
      almond.ico
  11. 6 37
      gradientchoosedialog.cpp
  12. 4 22
      gradients/clouds.xml
  13. 14 0
      gradients/default.xml
  14. 12 0
      gradients/rainbow.xml
  15. 7 7
      libmandel/include/ClGenerators.h
  16. 14 4
      libmandel/include/Mandel.h
  17. 102 76
      libmandel/src/ClGenerators.cpp
  18. 56 29
      libmandel/src/mandel.cpp

+ 35 - 30
Almond.cpp

@@ -23,36 +23,6 @@ Almond::Almond(QWidget *parent) :
     //mw->show();
 }
 
-void Almond::on_pushButton_clicked()
-{
-    ExportImageDialog dialog(this);
-    //dialog.show();
-    auto response = dialog.exec();
-    if (response == 1) {
-        mnd::MandelInfo mi;
-        mi.maxIter = dialog.getMaxIterations();
-        mi.view = mw->getViewport();
-        mi.bWidth = dialog.getWidth();
-        mi.bHeight = dialog.getHeight();
-        mi.view.adjustAspectRatio(mi.bWidth, mi.bHeight);
-        mnd::Generator& g = mandelContext.getCpuGeneratorFloat();
-        auto fmap = Bitmap<float>(mi.bWidth, mi.bHeight);
-        g.generate(mi, fmap.pixels.get());
-        auto bitmap = fmap.map<RGBColor>([&mi, this] (float i) {
-            return i >= mi.maxIter ? RGBColor{ 0,0,0 } : mw->getGradient().get(i);
-        });
-        QImage img((unsigned char*) bitmap.pixels.get(), bitmap.width, bitmap.height, bitmap.width * 3, QImage::Format_RGB888);
-        img.save(dialog.getPath());
-    }
-}
-
-
-void Almond::on_pushButton_2_clicked()
-{
-    BenchmarkDialog bd(mandelContext, this);
-    //bd.show();
-    bd.exec();
-}
 
 void Almond::on_zoom_out_clicked()
 {
@@ -106,3 +76,38 @@ void Almond::on_exportVideo_clicked()
         img.save(dialog.getPath());*/
     }
 }
+
+void Almond::on_smooth_stateChanged(int checked)
+{
+    this->mw->setSmoothColoring(checked != Qt::Unchecked);
+}
+
+void Almond::on_runBenchmark_clicked()
+{
+    BenchmarkDialog bd(mandelContext, this);
+    //bd.show();
+    bd.exec();
+}
+
+void Almond::on_exportImage_clicked()
+{
+    ExportImageDialog dialog(this);
+    //dialog.show();
+    auto response = dialog.exec();
+    if (response == 1) {
+        mnd::MandelInfo mi;
+        mi.maxIter = dialog.getMaxIterations();
+        mi.view = mw->getViewport();
+        mi.bWidth = dialog.getWidth();
+        mi.bHeight = dialog.getHeight();
+        mi.view.adjustAspectRatio(mi.bWidth, mi.bHeight);
+        mnd::Generator& g = mandelContext.getCpuGeneratorFloat();
+        auto fmap = Bitmap<float>(mi.bWidth, mi.bHeight);
+        g.generate(mi, fmap.pixels.get());
+        auto bitmap = fmap.map<RGBColor>([&mi, this] (float i) {
+            return i >= mi.maxIter ? RGBColor{ 0,0,0 } : mw->getGradient().get(i);
+        });
+        QImage img((unsigned char*) bitmap.pixels.get(), bitmap.width, bitmap.height, bitmap.width * 3, QImage::Format_RGB888);
+        img.save(dialog.getPath());
+    }
+}

+ 6 - 4
Almond.h

@@ -21,10 +21,6 @@ public:
     Almond(QWidget *parent = Q_NULLPTR);
 
 private slots:
-    void on_pushButton_clicked();
-
-    void on_pushButton_2_clicked();
-
     void on_zoom_out_clicked();
 
     void on_zoom_in_clicked();
@@ -35,6 +31,12 @@ private slots:
 
     void on_exportVideo_clicked();
 
+    void on_smooth_stateChanged(int arg1);
+
+    void on_runBenchmark_clicked();
+
+    void on_exportImage_clicked();
+
 private:
     Ui::AlmondClass ui;
 };

+ 1 - 0
Almond.pro

@@ -10,6 +10,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 
 TARGET = Almond
 TEMPLATE = app
+RC_ICONS = almond.ico
 # The following define makes your compiler emit warnings if you use
 # any feature of Qt which has been marked as deprecated (the exact warnings
 # depend on your compiler). Please consult the documentation of the

+ 3 - 1
Almond.qrc

@@ -1,5 +1,7 @@
 <RCC>
-    <qresource prefix="Almond">
+    <qresource prefix="gradients">
+        <file alias="default">gradients/default.xml</file>
         <file alias="clouds">gradients/clouds.xml</file>
+        <file alias="rainbow">gradients/rainbow.xml</file>
     </qresource>
 </RCC>

+ 65 - 27
Almond.ui

@@ -9,8 +9,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>666</width>
-    <height>563</height>
+    <width>763</width>
+    <height>524</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -23,22 +23,22 @@
       <item>
        <layout class="QVBoxLayout" name="verticalLayout_left">
         <item>
-         <layout class="QHBoxLayout" name="horizontalLayout_3">
-          <item>
-           <widget class="QPushButton" name="chooseGradient">
-            <property name="text">
-             <string>Choose Gradient</string>
-            </property>
-           </widget>
-          </item>
-          <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_3"/>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_right">
+        <item>
+         <layout class="QFormLayout" name="formLayout">
+          <item row="1" column="0">
            <widget class="QLabel" name="label">
             <property name="text">
-             <string>Max. Iterations</string>
+             <string>max. iterations</string>
             </property>
            </widget>
           </item>
-          <item>
+          <item row="1" column="1">
            <widget class="QLineEdit" name="maxIterations">
             <property name="text">
              <string>2000</string>
@@ -48,35 +48,66 @@
             </property>
            </widget>
           </item>
-          <item>
-           <widget class="QPushButton" name="zoom_in">
+          <item row="0" column="0" colspan="2">
+           <widget class="QPushButton" name="chooseGradient">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
             <property name="text">
-             <string>Zoom In</string>
+             <string>Choose Gradient</string>
             </property>
            </widget>
           </item>
-          <item>
-           <widget class="QPushButton" name="zoom_out">
+          <item row="2" column="0" colspan="2">
+           <widget class="QCheckBox" name="smooth">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
             <property name="text">
-             <string>Zoom Out</string>
+             <string>smooth coloring</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
             </property>
            </widget>
           </item>
          </layout>
         </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QVBoxLayout" name="verticalLayout_right">
         <item>
-         <widget class="QPushButton" name="pushButton_2">
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="QPushButton" name="zoom_in">
           <property name="text">
-           <string>Run Benchmark</string>
+           <string>Zoom In</string>
           </property>
          </widget>
         </item>
         <item>
-         <spacer name="verticalSpacer">
+         <widget class="QPushButton" name="zoom_out">
+          <property name="text">
+           <string>Zoom Out</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="verticalSpacer_2">
           <property name="orientation">
            <enum>Qt::Vertical</enum>
           </property>
@@ -89,6 +120,13 @@
          </spacer>
         </item>
         <item>
+         <widget class="QPushButton" name="runBenchmark">
+          <property name="text">
+           <string>Run Benchmark</string>
+          </property>
+         </widget>
+        </item>
+        <item>
          <widget class="QPushButton" name="exportVideo">
           <property name="text">
            <string>Export Video</string>
@@ -96,7 +134,7 @@
          </widget>
         </item>
         <item>
-         <widget class="QPushButton" name="pushButton">
+         <widget class="QPushButton" name="exportImage">
           <property name="text">
            <string>Export Image</string>
           </property>

+ 35 - 214
Gradient.cpp

@@ -2,116 +2,9 @@
 
 #include <cmath>
 #include <algorithm>
+#include <QtXml/QDomDocument>
+#include <QFile>
 
-/*
-Gradient::Gradient()
-{
-    //addColor(RGBColor{255, 0, 0}, -100);
-    addColor(RGBColor{0, 0, 0}, 0);
-    addColor(RGBColor{ 250, 70, 24 }, 40);
-    addColor(RGBColor{ 200, 230, 30 }, 104);
-    addColor(RGBColor{ 70, 223, 30 }, 190);
-    addColor(RGBColor{ 14, 20, 150 }, 295);
-    addColor(RGBColor{ 36, 155, 169 }, 418);
-    addColor(RGBColor{ 233, 33, 79 }, 558);
-    addColor(RGBColor{ 254, 169, 63 }, 714);
-    addColor(RGBColor{ 227, 93, 201 }, 885);
-    addColor(RGBColor{ 188, 24, 161 }, 1071);
-    addColor(RGBColor{ 45, 225, 44 }, 1271);
-    addColor(RGBColor{ 52, 58, 250 }, 1485);
-    addColor(RGBColor{ 87, 93, 241 }, 1712);
-    addColor(RGBColor{ 6, 37, 208 }, 1952);
-    addColor(RGBColor{ 193, 164, 162 }, 2205);
-    addColor(RGBColor{ 49, 8, 90 }, 2471);
-    addColor(RGBColor{ 124, 149, 120 }, 2749);
-    addColor(RGBColor{ 56, 69, 6 }, 3039);
-    addColor(RGBColor{ 231, 177, 252 }, 3341);
-    addColor(RGBColor{ 36, 76, 95 }, 3655);
-    addColor(RGBColor{ 1, 99, 184 }, 3980);
-    addColor(RGBColor{ 74, 223, 199 }, 4316);
-    addColor(RGBColor{ 249, 125, 31 }, 4664);
-    addColor(RGBColor{ 28, 93, 214 }, 5023);
-    addColor(RGBColor{ 232, 117, 145 }, 5393);
-    addColor(RGBColor{ 208, 158, 49 }, 5773);
-    addColor(RGBColor{ 218, 109, 177 }, 6164);
-    addColor(RGBColor{ 139, 83, 177 }, 6565);
-    addColor(RGBColor{ 16, 36, 59 }, 6977);
-    addColor(RGBColor{ 194, 157, 26 }, 7399);
-    addColor(RGBColor{ 77, 236, 12 }, 7831);
-    addColor(RGBColor{ 124, 244, 151 }, 8273);
-    addColor(RGBColor{ 128, 195, 162 }, 8725);
-    addColor(RGBColor{ 66, 36, 194 }, 9187);
-    addColor(RGBColor{ 81, 151, 185 }, 9659);
-    addColor(RGBColor{ 173, 75, 175 }, 10140);
-    addColor(RGBColor{ 43, 182, 52 }, 10631);
-    addColor(RGBColor{ 14, 242, 141 }, 11131);
-    addColor(RGBColor{ 156, 203, 87 }, 11641);
-    addColor(RGBColor{ 147, 89, 150 }, 12160);
-    addColor(RGBColor{ 213, 199, 183 }, 12689);
-    addColor(RGBColor{ 186, 255, 52 }, 13227);
-    addColor(RGBColor{ 28, 158, 154 }, 13774);
-    addColor(RGBColor{ 5, 5, 116 }, 14330);
-    addColor(RGBColor{ 126, 123, 232 }, 14895);
-    addColor(RGBColor{ 43, 162, 251 }, 15469);
-    addColor(RGBColor{ 198, 143, 125 }, 16052);
-    addColor(RGBColor{ 201, 157, 178 }, 16644);
-    addColor(RGBColor{ 213, 151, 189 }, 17245);
-    addColor(RGBColor{ 188, 117, 169 }, 17854);
-    addColor(RGBColor{ 156, 189, 249 }, 18472);
-    addColor(RGBColor{ 62, 23, 33 }, 19099);
-    addColor(RGBColor{ 167, 205, 74 }, 19734);
-    addColor(RGBColor{ 161, 181, 210 }, 20378);
-    addColor(RGBColor{ 179, 167, 215 }, 21030);
-    addColor(RGBColor{ 204, 102, 126 }, 21691);
-    addColor(RGBColor{ 123, 49, 127 }, 22360);
-    addColor(RGBColor{ 178, 48, 136 }, 23037);
-    addColor(RGBColor{ 108, 112, 99 }, 23723);
-    addColor(RGBColor{ 250, 152, 78 }, 24417);
-    addColor(RGBColor{ 79, 167, 196 }, 25119);
-    addColor(RGBColor{ 149, 167, 8 }, 25829);
-    addColor(RGBColor{ 196, 29, 159 }, 26548);
-    addColor(RGBColor{ 128, 26, 20 }, 27275);
-    addColor(RGBColor{ 69, 49, 66 }, 28010);
-    addColor(RGBColor{ 12, 42, 198 }, 28753);
-    addColor(RGBColor{ 61, 62, 36 }, 29504);
-    addColor(RGBColor{ 27, 94, 114 }, 30263);
-    addColor(RGBColor{ 54, 218, 7 }, 31030);
-    addColor(RGBColor{ 105, 89, 170 }, 31804);
-    addColor(RGBColor{ 100, 110, 2 }, 32586);
-    addColor(RGBColor{ 208, 198, 148 }, 33376);
-    addColor(RGBColor{ 80, 208, 131 }, 34174);
-    addColor(RGBColor{ 176, 89, 59 }, 34980);
-    addColor(RGBColor{ 255, 64, 243 }, 35793);
-    addColor(RGBColor{ 39, 226, 232 }, 36614);
-    addColor(RGBColor{ 154, 100, 238 }, 37443);
-    addColor(RGBColor{ 53, 103, 192 }, 38279);
-    addColor(RGBColor{ 187, 41, 136 }, 39123);
-    addColor(RGBColor{ 33, 84, 227 }, 39974);
-    addColor(RGBColor{ 71, 167, 211 }, 40833);
-    addColor(RGBColor{ 55, 191, 255 }, 41699);
-    addColor(RGBColor{ 60, 165, 201 }, 42573);
-    addColor(RGBColor{ 231, 206, 192 }, 43454);
-    addColor(RGBColor{ 233, 224, 197 }, 44343);
-    addColor(RGBColor{ 255, 129, 13 }, 45239);
-    addColor(RGBColor{ 131, 222, 95 }, 46143);
-    addColor(RGBColor{ 155, 249, 72 }, 47054);
-    addColor(RGBColor{ 248, 129, 30 }, 47972);
-    addColor(RGBColor{ 48, 239, 206 }, 48898);
-    addColor(RGBColor{ 176, 224, 64 }, 49831);
-    addColor(RGBColor{ 155, 12, 162 }, 50771);
-    addColor(RGBColor{ 6, 144, 149 }, 51718);
-    addColor(RGBColor{ 231, 208, 16 }, 52672);
-    addColor(RGBColor{ 190, 66, 231 }, 53634);
-    addColor(RGBColor{ 19, 17, 253 }, 54603);
-    addColor(RGBColor{ 4, 34, 60 }, 55579);
-    addColor(RGBColor{ 101, 23, 88 }, 56562);
-    addColor(RGBColor{ 9, 191, 235 }, 57552);
-
-
-    max = 10000;
-    //addColor(RGBColor{255, 0, 255}, 1000000000.0f);
-}
-*/
 
 Gradient::Gradient(void) :
     max{ 1.0 }
@@ -119,7 +12,8 @@ Gradient::Gradient(void) :
 }
 
 
-Gradient::Gradient(const std::vector<std::pair<RGBColor, float>>& colors, int precalcSteps)
+Gradient::Gradient(const std::vector<std::pair<RGBColor, float>>& colors, bool repeat, int precalcSteps) :
+    repeat{ repeat }
 {
     if(colors.empty())
         return;
@@ -156,110 +50,33 @@ Gradient::Gradient(const std::vector<std::pair<RGBColor, float>>& colors, int pr
 
 Gradient Gradient::defaultGradient(void)
 {
-    std::vector<std::pair<RGBColor, float>> colors = {
-        { RGBColor{0, 0, 0}, 0 },
-        { RGBColor{ 250, 70, 24 }, 40 },
-        { RGBColor{ 200, 230, 30 }, 80 },
-        { RGBColor{ 70, 223, 30 }, 105 },
-        { RGBColor{ 40, 190, 240 }, 140 },
-        { RGBColor{ 120, 60, 160 }, 230 },
-        { RGBColor{ 14, 20, 180 }, 300 },
-        { RGBColor{ 240, 240, 240 }, 418 },
-        { RGBColor{ 243, 20, 20 }, 558 },
-        { RGBColor{ 254, 169, 63 }, 714 },
-        { RGBColor{ 8, 50, 8 }, 885 },
-        { RGBColor{ 188, 5, 161 }, 1071 },
-        { RGBColor{ 45, 225, 44 }, 1271 },
-        { RGBColor{ 52, 58, 250 }, 1485 },
-        { RGBColor{ 87, 93, 241 }, 1712 },
-        { RGBColor{ 6, 37, 208 }, 1952 },
-        { RGBColor{ 193, 164, 162 }, 2205 },
-        { RGBColor{ 49, 8, 90 }, 2471 },
-        { RGBColor{ 124, 149, 120 }, 2749 },
-        { RGBColor{ 56, 69, 6 }, 3039 },
-        { RGBColor{ 231, 177, 252 }, 3341 },
-        { RGBColor{ 36, 76, 95 }, 3655 },
-        { RGBColor{ 1, 99, 184 }, 3980 },
-        { RGBColor{ 74, 223, 199 }, 4316 },
-        { RGBColor{ 249, 125, 31 }, 4664 },
-        { RGBColor{ 28, 93, 214 }, 5023 },
-        { RGBColor{ 232, 117, 145 }, 5393 },
-        { RGBColor{ 208, 158, 49 }, 5773 },
-        { RGBColor{ 218, 109, 177 }, 6164 },
-        { RGBColor{ 139, 83, 177 }, 6565 },
-        { RGBColor{ 16, 36, 59 }, 6977 },
-        { RGBColor{ 194, 157, 26 }, 7399 },
-        { RGBColor{ 77, 236, 12 }, 7831 },
-        { RGBColor{ 124, 244, 151 }, 8273 },
-        { RGBColor{ 128, 195, 162 }, 8725 },
-        { RGBColor{ 66, 36, 194 }, 9187 },
-        { RGBColor{ 81, 151, 185 }, 9659 },
-        { RGBColor{ 173, 75, 175 }, 10140 },
-        { RGBColor{ 43, 182, 52 }, 10631 },
-        { RGBColor{ 14, 242, 141 }, 11131 },
-        { RGBColor{ 156, 203, 87 }, 11641 },
-        { RGBColor{ 147, 89, 150 }, 12160 },
-        { RGBColor{ 213, 199, 183 }, 12689 },
-        { RGBColor{ 186, 255, 52 }, 13227 },
-        { RGBColor{ 28, 158, 154 }, 13774 },
-        { RGBColor{ 5, 5, 116 }, 14330 },
-        { RGBColor{ 126, 123, 232 }, 14895 },
-        { RGBColor{ 43, 162, 251 }, 15469 },
-        { RGBColor{ 198, 143, 125 }, 16052 },
-        { RGBColor{ 201, 157, 178 }, 16644 },
-        { RGBColor{ 213, 151, 189 }, 17245 },
-        { RGBColor{ 188, 117, 169 }, 17854 },
-        { RGBColor{ 156, 189, 249 }, 18472 },
-        { RGBColor{ 62, 23, 33 }, 19099 },
-        { RGBColor{ 167, 205, 74 }, 19734 },
-        { RGBColor{ 161, 181, 210 }, 20378 },
-        { RGBColor{ 179, 167, 215 }, 21030 },
-        { RGBColor{ 204, 102, 126 }, 21691 },
-        { RGBColor{ 123, 49, 127 }, 22360 },
-        { RGBColor{ 178, 48, 136 }, 23037 },
-        { RGBColor{ 108, 112, 99 }, 23723 },
-        { RGBColor{ 250, 152, 78 }, 24417 },
-        { RGBColor{ 79, 167, 196 }, 25119 },
-        { RGBColor{ 149, 167, 8 }, 25829 },
-        { RGBColor{ 196, 29, 159 }, 26548 },
-        { RGBColor{ 128, 26, 20 }, 27275 },
-        { RGBColor{ 69, 49, 66 }, 28010 },
-        { RGBColor{ 12, 42, 198 }, 28753 },
-        { RGBColor{ 61, 62, 36 }, 29504 },
-        { RGBColor{ 27, 94, 114 }, 30263 },
-        { RGBColor{ 54, 218, 7 }, 31030 },
-        { RGBColor{ 105, 89, 170 }, 31804 },
-        { RGBColor{ 100, 110, 2 }, 32586 },
-        { RGBColor{ 208, 198, 148 }, 33376 },
-        { RGBColor{ 80, 208, 131 }, 34174 },
-        { RGBColor{ 176, 89, 59 }, 34980 },
-        { RGBColor{ 255, 64, 243 }, 35793 },
-        { RGBColor{ 39, 226, 232 }, 36614 },
-        { RGBColor{ 154, 100, 238 }, 37443 },
-        { RGBColor{ 53, 103, 192 }, 38279 },
-        { RGBColor{ 187, 41, 136 }, 39123 },
-        { RGBColor{ 33, 84, 227 }, 39974 },
-        { RGBColor{ 71, 167, 211 }, 40833 },
-        { RGBColor{ 55, 191, 255 }, 41699 },
-        { RGBColor{ 60, 165, 201 }, 42573 },
-        { RGBColor{ 231, 206, 192 }, 43454 },
-        { RGBColor{ 233, 224, 197 }, 44343 },
-        { RGBColor{ 255, 129, 13 }, 45239 },
-        { RGBColor{ 131, 222, 95 }, 46143 },
-        { RGBColor{ 155, 249, 72 }, 47054 },
-        { RGBColor{ 248, 129, 30 }, 47972 },
-        { RGBColor{ 48, 239, 206 }, 48898 },
-        { RGBColor{ 176, 224, 64 }, 49831 },
-        { RGBColor{ 155, 12, 162 }, 50771 },
-        { RGBColor{ 6, 144, 149 }, 51718 },
-        { RGBColor{ 231, 208, 16 }, 52672 },
-        { RGBColor{ 190, 66, 231 }, 53634 },
-        { RGBColor{ 19, 17, 253 }, 54603 },
-        { RGBColor{ 4, 34, 60 }, 55579 },
-        { RGBColor{ 101, 23, 88 }, 56562 },
-        { RGBColor{ 9, 191, 235 }, 57552 }
-    };
-    return Gradient{ colors };
+    QFile res(":/gradients/default");
+    res.open(QIODevice::ReadOnly);
+    QString str = QString::fromUtf8(res.readAll());
+    return readXml(str);
+}
+
+Gradient Gradient::readXml(const QString& xml)
+{
+    QDomDocument xsr;
+    xsr.setContent(xml);
+    auto elem = xsr.documentElement();
+    auto repeatAttr = elem.attributeNode("repeat");
+    bool repeat = !repeatAttr.isNull() && repeatAttr.value().toLower() == "true";
+    auto colors = xsr.elementsByTagName("color");
+    std::vector<std::pair<RGBColor, float>> colorArr;
+    for (int i = 0; i < colors.length(); ++i) {
+        auto child = colors.item(i).toElement();
+        uint8_t r = child.attributeNode("r").value().toInt();
+        uint8_t g = child.attributeNode("g").value().toInt();
+        uint8_t b = child.attributeNode("b").value().toInt();
+        float p = child.attributeNode("p").value().toInt();
+
+        printf("rgb (%s): %d, %d, %d\n", child.text().toUtf8().data(), r, g, b);
+        colorArr.push_back({ { r, g, b }, p });
+    }
+
+    return Gradient(colorArr, repeat);
 }
 
 
@@ -271,6 +88,10 @@ RGBColor Gradient::get(float x) const
     RGBColor lerped = lerpColors(left, right, lerp);
     return lerped;*/
 
+    if (x > this->max) {
+        if (repeat)
+            x = ::fmodf(x, this->max);
+    }
     float pos = x * colors.size() / max;
     if (pos < 0) {
         pos = 0;

+ 5 - 1
Gradient.h

@@ -1,6 +1,7 @@
 #ifndef GRADIENT_H
 #define GRADIENT_H
 
+#include <QString>
 #include <vector>
 #include "Color.h"
 #include <tuple>
@@ -13,12 +14,15 @@ class Gradient
     /// so they can be easily interpolated
     std::vector<RGBColor> colors;
     float max;
+    bool repeat;
 public:
     Gradient(void);
-    Gradient(const std::vector<std::pair<RGBColor, float>>&, int precalcSteps = 10000);
+    Gradient(const std::vector<std::pair<RGBColor, float>>&, bool repeat = false, int precalcSteps = 10000);
 
     static Gradient defaultGradient(void);
 
+    static Gradient readXml(const QString& xml);
+
     /*!
      * \brief get a color at a specific position in this gradient
      * \param x the position

+ 41 - 11
MandelWidget.cpp

@@ -214,11 +214,11 @@ void Job::run(void)
     mi.view.width = mi.view.height = gw;
     mi.bWidth = mi.bHeight = MandelView::chunkSize;
     mi.maxIter = maxIter;
-    mndContext.getDefaultGenerator().generate(mi, f.pixels.get());
+    generator->generate(mi, f.pixels.get());
     auto* rgb = new Bitmap<RGBColor>(f.map<RGBColor>([&mi, this](float i) {
         return i >= mi.maxIter ? RGBColor{ 0, 0, 0 } : gradient.get(i);
     }));
-    emit done(level, i, j, rgb);
+    emit done(level, i, j, calcState, rgb);
 }
 
 
@@ -239,7 +239,7 @@ void Calcer::calc(TexGrid& grid, int level, GridIndex i, GridIndex j, int priori
 {
     jobsMutex.lock();
     if (jobs.find({ level, i, j }) == jobs.end()) {
-        Job* job = new Job(mndContext, gradient, maxIter, &grid, level, i, j);
+        Job* job = new Job(generator, gradient, maxIter, &grid, level, i, j, calcState);
         connect(job, &Job::done, this, &Calcer::redirect);
         connect(job, &QObject::destroyed, this, [this, level, i, j] () { this->notFinished(level, i, j); });
         jobs.emplace(std::tuple{level, i, j}, job);
@@ -279,19 +279,24 @@ void Calcer::notFinished(int level, GridIndex i, GridIndex j)
 }
 
 
-void Calcer::redirect(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp)
+void Calcer::redirect(int level, GridIndex i, GridIndex j, long calcState, Bitmap<RGBColor>* bmp)
 {
     jobsMutex.lock();
     jobs.erase({ level, i, j });
     jobsMutex.unlock();
-    emit done(level, i, j, bmp);
+    if (this->calcState == calcState) {
+        emit done(level, i, j, bmp);
+    }
+    else {
+        delete bmp;
+    }
 }
 
 
-MandelView::MandelView(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter) :
-    mndContext{ mndContext },
-    calcer{ mndContext, gradient, maxIter },
-    gradient{ gradient },
+MandelView::MandelView(mnd::Generator* generator, MandelWidget& owner, int maxIter) :
+    generator{ generator },
+    calcer{ generator, owner.getGradient(), maxIter },
+    owner{ owner },
     maxIter{ maxIter }
 {
     Bitmap<RGBColor> emp(8, 8);
@@ -343,6 +348,16 @@ void MandelView::setMaxIter(int maxIter)
 }
 
 
+void MandelView::setGenerator(mnd::Generator* generator)
+{
+    if (this->generator != generator) {
+        this->generator = generator;
+        calcer.setGenerator(generator);
+        clearCells();
+        emit redrawRequested();
+    }
+}
+
 
 void MandelView::clearCells(void)
 {
@@ -552,11 +567,26 @@ MandelWidget::~MandelWidget()
 void MandelWidget::setGradient(Gradient g)
 {
     this->gradient = std::move(g);
-    this->mandelView->clearCells();
+    if (mandelView) {
+        mandelView->clearCells();
+        mandelView->calcer.changeState();
+    }
     emit update();
 }
 
 
+void MandelWidget::setSmoothColoring(bool sc)
+{
+    if (sc != this->smoothColoring) {
+        this->smoothColoring = sc;
+        if (mandelView) {
+            mandelView->clearCells();
+            mandelView->setGenerator(&mndContext.getDefaultGenerator(smoothColoring));
+        }
+    }
+}
+
+
 void MandelWidget::initializeGL(void)
 {
     this->context()->functions()->glClearColor(0, 0, 0, 0);
@@ -577,7 +607,7 @@ void MandelWidget::initializeGL(void)
 void MandelWidget::paintGL(void)
 {
     if (mandelView == nullptr) {
-        mandelView = std::make_unique<MandelView>(mndContext, gradient, maxIterations);
+        mandelView = std::make_unique<MandelView>(&mndContext.getDefaultGenerator(smoothColoring), *this, maxIterations);
         QObject::connect(mandelView.get(), &MandelView::redrawRequested, this, static_cast<void(QOpenGLWidget::*)(void)>(&QOpenGLWidget::update));
     }
 

+ 35 - 17
MandelWidget.h

@@ -26,6 +26,10 @@
 using GridIndex = long long;
 Q_DECLARE_METATYPE(GridIndex)
 
+
+class MandelView;
+class MandelWidget;
+
 class Texture
 {
     GLuint id;
@@ -138,7 +142,6 @@ struct GridElement
 };
 
 
-class MandelView;
 
 
 class TexGrid
@@ -166,29 +169,32 @@ class Job : public QObject, public QRunnable
 {
     Q_OBJECT
 public:
-    mnd::MandelContext& mndContext;
-    Gradient& gradient;
+    mnd::Generator* generator;
+    const Gradient& gradient;
     int maxIter;
     TexGrid* grid;
     int level;
     GridIndex i, j;
+    long calcState = 0;
 
-    inline Job(mnd::MandelContext& mndContext,
-               Gradient& gradient,
+    inline Job( mnd::Generator* generator,
+               const Gradient& gradient,
                int maxIter,
                TexGrid* grid,
-               int level, GridIndex i, GridIndex j) :
-        mndContext{ mndContext },
+               int level, GridIndex i, GridIndex j,
+               long calcState) :
+        generator{ generator },
         gradient{ gradient },
         maxIter{ maxIter },
         grid{ grid },
         level{ level },
-        i{ i }, j{ j }
+        i{ i }, j{ j },
+        calcState{ calcState }
     {}
 
     void run() override;
 signals:
-    void done(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp);
+    void done(int level, GridIndex i, GridIndex j, long calcState, Bitmap<RGBColor>* bmp);
 };
 
 
@@ -198,15 +204,17 @@ class Calcer : public QObject
     /// tuple contains level, i, j of the job
     std::unordered_map<std::tuple<int, GridIndex, GridIndex>, Job*, TripleHash> jobs;
     QMutex jobsMutex;
-    mnd::MandelContext& mndContext;
+    mnd::Generator* generator;
     std::unique_ptr<QThreadPool> threadPool;
-    Gradient& gradient;
+    const Gradient& gradient;
     int maxIter;
     int currentLevel;
+
+    volatile long calcState = 0;
 public:
-    inline Calcer(mnd::MandelContext& mc, Gradient& gradient, int maxIter) :
+    inline Calcer(mnd::Generator* generator, const Gradient& gradient, int maxIter) :
         jobsMutex{ QMutex::Recursive },
-        mndContext{ mc },
+        generator{ generator },
         threadPool{ std::make_unique<QThreadPool>() },
         gradient{ gradient },
         maxIter{ maxIter }
@@ -216,12 +224,15 @@ public:
 
     void setMaxIter(int maxIter);
     void clearAll(void);
+    void setGenerator(mnd::Generator* generator) { this->generator = generator; changeState(); }
+
+    inline void changeState(void) { calcState++; }
 
 public slots:
     void calc(TexGrid& grid, int level, GridIndex i, GridIndex j, int priority);
     void setCurrentLevel(int level);
     void notFinished(int level, GridIndex i, GridIndex j);
-    void redirect(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp);
+    void redirect(int level, GridIndex i, GridIndex j, long calcState, Bitmap<RGBColor>* bmp);
 signals:
     void done(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp);
 };
@@ -236,15 +247,15 @@ public:
     // a grid should not be deleted once constructed.
     // to free up memory one can call TexGrid::clearCells()
     std::unordered_map<int, TexGrid> levels;
-    mnd::MandelContext& mndContext;
+    mnd::Generator* generator;
     Calcer calcer;
-    Gradient& gradient;
+    MandelWidget& owner;
     int maxIter;
     int width;
     int height;
 public:
     static const int chunkSize = 256;
-    MandelView(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter);
+    MandelView(mnd::Generator* generator, MandelWidget& owner, int maxIter);
     int getLevel(double dpp);
     double getDpp(int level);
 
@@ -253,6 +264,8 @@ public:
     inline int getMaxIter(void) const { return this->maxIter; }
     void setMaxIter(int maxIter);
 
+    void setGenerator(mnd::Generator* generator);
+
     void clearCells(void);
 
     void garbageCollect(int level, GridIndex i, GridIndex j);
@@ -272,6 +285,8 @@ class MandelWidget : public QOpenGLWidget
 private:
     mnd::MandelContext& mndContext;
 
+    bool smoothColoring = true;
+
     Gradient gradient;
 
     bool initialized = false;
@@ -295,6 +310,9 @@ public:
     inline const Gradient& getGradient(void) const { return gradient; }
     void setGradient(Gradient g);
 
+    inline bool getSmoothColoring(void) const { return smoothColoring; }
+    void setSmoothColoring(bool sc);
+
     void initializeGL(void) override;
 
     void resizeGL(int w, int h) override;

BIN
almond.ico


+ 6 - 37
gradientchoosedialog.cpp

@@ -1,6 +1,5 @@
 #include "gradientchoosedialog.h"
 
-#include <QtXml/QDomDocument>
 #include <QFile>
 #include <QResource>
 #include <QDir>
@@ -21,46 +20,15 @@ GradientChooseDialog::GradientChooseDialog()
     f.setStyleHint(QFont::Monospace);
     gcd.plainTextEdit->setFont(f);
 
-
-    QFile qf(":/Almond/clouds");
-    QString str = QString::fromUtf8(qf.readAll());
-    printf("%s\n", str.toStdString().c_str());
+    gcd.presets->addItem("default");
     gcd.presets->addItem("clouds");
-    gcd.presets->addItem("none");
+    gcd.presets->addItem("rainbow");
 }
 
-#if 0
-
-<gradient>
-  <color r="230" g="10" b="40" p="0" />
-  <color r="30" g="230" b="80" p="100" />
-  <color r="20" g="120" b="210" p="500" />
-</gradient>
-
-#endif
 
 void GradientChooseDialog::on_buttonBox_accepted()
 {
-    QDomDocument xsr;
-    xsr.setContent(gcd.plainTextEdit->toPlainText());
-    auto elem = xsr.documentElement();
-    auto colors = xsr.elementsByTagName("color");
-    std::vector<std::pair<RGBColor, float>> colorArr;
-    for (int i = 0; i < colors.length(); ++i) {
-        auto child = colors.item(i).toElement();
-        uint8_t r = child.attributeNode("r").value().toInt();
-        uint8_t g = child.attributeNode("g").value().toInt();
-        uint8_t b = child.attributeNode("b").value().toInt();
-        float p = child.attributeNode("p").value().toInt();
-
-        printf("rgb (%s): %d, %d, %d\n", child.text().toUtf8().data(), r, g, b);
-        colorArr.push_back({ { r, g, b }, p });
-    }
-
-    chosenGradient = std::make_unique<Gradient>(colorArr);
-
-    printf("yee: %s\n", elem.text().toUtf8().data());
-    fflush(stdout);
+    chosenGradient = std::make_unique<Gradient>(Gradient::readXml(gcd.plainTextEdit->toPlainText()));
 }
 
 
@@ -71,7 +39,8 @@ void GradientChooseDialog::on_buttonBox_clicked(QAbstractButton *button)
 
 void GradientChooseDialog::on_presets_currentIndexChanged(const QString& index)
 {
-    QResource gr(":/gradients/clouds.xml");
-    QString str = QString::fromUtf8(reinterpret_cast<const char*>(gr.data()));
+    QFile res(":/gradients/" + index);
+    res.open(QIODevice::ReadOnly);
+    QString str = QString::fromUtf8(res.readAll());
     emit gcd.plainTextEdit->setPlainText(str);
 }

+ 4 - 22
gradients/clouds.xml

@@ -1,23 +1,5 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<gradient>
-<color r="255" g="255" b="255" p="0" />
-<color r="200" g="200" b="255" p="50" />
-<color r="255" g="255" b="255" p="100" />
-<color r="200" g="200" b="255" p="150" />
-<color r="255" g="255" b="255" p="200" />
-<color r="200" g="200" b="255" p="250" />
-<color r="255" g="255" b="255" p="300" />
-<color r="200" g="200" b="255" p="350" />
-<color r="255" g="255" b="255" p="400" />
-<color r="200" g="200" b="255" p="450" />
-<color r="255" g="255" b="255" p="500" />
-<color r="200" g="200" b="255" p="550" />
-<color r="255" g="255" b="255" p="600" />
-<color r="200" g="200" b="255" p="650" />
-<color r="255" g="255" b="255" p="700" />
-<color r="200" g="200" b="255" p="750" />
-<color r="255" g="255" b="255" p="800" />
-<color r="200" g="200" b="255" p="850" />
-<color r="255" g="255" b="255" p="900" />
-<color r="200" g="200" b="255" p="950" />
+<gradient repeat="true">
+    <color r="255" g="255" b="255" p="0" />
+    <color r="120" g="170" b="255" p="50" />
+    <color r="255" g="255" b="255" p="100" />
 </gradient>

+ 14 - 0
gradients/default.xml

@@ -0,0 +1,14 @@
+<gradient repeat="true">
+    <color r="0" g="0" b="0" p="0" />
+    <color r="250" g="70" b="24" p="40" />
+    <color r="200" g="230" b="30" p="80" />
+    <color r="70" g="223" b="30" p="105" />
+    <color r="40" g="190" b="240" p="140" />
+    <color r="120" g="60" b="160" p="230" />
+    <color r="14" g="20" b="180" p="300" />
+    <color r="240" g="240" b="240" p="418" />
+    <color r="243" g="20" b="20" p="558" />
+    <color r="254" g="169" b="63" p="714" />
+    <color r="8" g="50" b="8" p="885" />
+    <color r="0" g="0" b="0" p="950" />
+</gradient>

+ 12 - 0
gradients/rainbow.xml

@@ -0,0 +1,12 @@
+<gradient repeat="true">
+    <color r="255" g="255" b="255" p="0" />
+    <color r="210" g="210" b="210" p="3" />
+    <color r="150" g="150" b="150" p="7" />
+    <color r="255" g="0" b="0" p="10" />
+    <color r="255" g="255" b="0" p="15" />
+    <color r="0" g="255" b="0" p="20" />
+    <color r="0" g="255" b="255" p="25" />
+    <color r="0" g="0" b="255" p="30" />
+    <color r="255" g="0" b="255" p="35" />
+    <color r="255" g="255" b="255" p="40" />
+</gradient>

+ 7 - 7
libmandel/include/ClGenerators.h

@@ -34,42 +34,42 @@ public:
     virtual void generate(const MandelInfo& info, float* data);
 
 protected:
-    virtual std::string getKernelCode(void) const = 0;
+    virtual std::string getKernelCode(bool smooth) const = 0;
 };
 
 
 class mnd::ClGeneratorFloat : public ClGenerator
 {
 public:
-    ClGeneratorFloat(cl::Device device);
+    ClGeneratorFloat(cl::Device device, bool smooth);
     virtual ~ClGeneratorFloat(void) = default;
 
 protected:
-    virtual std::string getKernelCode(void) const;
+    virtual std::string getKernelCode(bool smooth) const;
 };
 
 
 class mnd::ClGeneratorDouble : public ClGenerator
 {
 public:
-    ClGeneratorDouble(cl::Device device);
+    ClGeneratorDouble(cl::Device device, bool smooth);
     virtual ~ClGeneratorDouble(void) = default;
 
     virtual void generate(const MandelInfo& info, float* data);
 protected:
-    virtual std::string getKernelCode(void) const;
+    virtual std::string getKernelCode(bool smooth) const;
 };
 
 
 class mnd::ClGenerator128 : public ClGenerator
 {
 public:
-    ClGenerator128(cl::Device device);
+    ClGenerator128(cl::Device device, bool smooth);
     virtual ~ClGenerator128(void) = default;
 
     virtual void generate(const MandelInfo& info, float* data);
 protected:
-    virtual std::string getKernelCode(void) const;
+    virtual std::string getKernelCode(bool smooth) const;
 };
 
 #endif // WITH_OPENCL

+ 14 - 4
libmandel/include/Mandel.h

@@ -31,15 +31,19 @@ private:
     std::unique_ptr<Generator> floatGenerator;
     std::unique_ptr<Generator> doubleGenerator;
     std::unique_ptr<Generator> generator128;
+    std::unique_ptr<Generator> floatGeneratorSmooth;
+    std::unique_ptr<Generator> doubleGeneratorSmooth;
+    std::unique_ptr<Generator> generator128Smooth;
+
     MandelDevice(void);
 public:
 
     inline const std::string& getVendor(void) const { return vendor; }
     const std::string& getName(void) const;
 
-    Generator* getGeneratorFloat(void) const;
-    Generator* getGeneratorDouble(void) const;
-    Generator* getGenerator128(void) const;
+    Generator* getGeneratorFloat(bool smooth = true) const;
+    Generator* getGeneratorDouble(bool smooth = true) const;
+    Generator* getGenerator128(bool smooth = true) const;
 };
 
 
@@ -55,7 +59,13 @@ private:
     std::unique_ptr<Generator> cpuGenerator128;
     std::unique_ptr<Generator> cpuGeneratorFixedp;
 
+    std::unique_ptr<Generator> cpuGeneratorFloatSmooth;
+    std::unique_ptr<Generator> cpuGeneratorDoubleSmooth;
+    std::unique_ptr<Generator> cpuGenerator128Smooth;
+    std::unique_ptr<Generator> cpuGeneratorFixedpSmooth;
+
     std::unique_ptr<Generator> adaptiveGenerator;
+    std::unique_ptr<Generator> adaptiveGeneratorSmooth;
 
     std::vector<MandelDevice> devices;
 
@@ -64,7 +74,7 @@ private:
     std::vector<MandelDevice> createDevices(void);
 public:
 
-    Generator& getDefaultGenerator(void);
+    Generator& getDefaultGenerator(bool smooth = true);
     const std::vector<MandelDevice>& getDevices(void);
 
     Generator& getCpuGeneratorFloat(void);

+ 102 - 76
libmandel/src/ClGenerators.cpp

@@ -109,7 +109,7 @@ void ClGenerator::generate(const mnd::MandelInfo& info, float* data)
 }
 
 
-ClGeneratorFloat::ClGeneratorFloat(cl::Device device) :
+ClGeneratorFloat::ClGeneratorFloat(cl::Device device, bool smooth) :
     ClGenerator{ device }
 {
     /*Platform p = getPlatform();
@@ -117,7 +117,7 @@ ClGeneratorFloat::ClGeneratorFloat(cl::Device device) :
     context = Context{ device };
     Program::Sources sources;
 
-    std::string kcode = this->getKernelCode();
+    std::string kcode = this->getKernelCode(smooth);
 
     sources.push_back({ kcode.c_str(), kcode.length() });
 
@@ -130,48 +130,41 @@ ClGeneratorFloat::ClGeneratorFloat(cl::Device device) :
 }
 
 
-std::string ClGeneratorFloat::getKernelCode(void) const
+std::string ClGeneratorFloat::getKernelCode(bool smooth) const
 {
-    if (false && device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT>() == 4) {
-        return
-            "__kernel void iterate(__global float* A, const int width, float xl, float yt, float pixelScaleX, float pixelScaleY, int max) {\n"
-            "   int index = get_global_id(0) * 4;\n"
-            "   int x = index % (width);\n"
-            "   int y = index / (width);\n"
-            "   float4 av = (float4)(x * pixelScaleX + xl, (x + 1) * pixelScaleX + xl, (x + 2) * pixelScaleX + xl, (x + 3) * pixelScaleX + xl);\n"
-    //                        "(x + 4) * pixelScale + xl, (x + 5) * pixelScale + xl, (x + 6) * pixelScale + xl, (x + 7) * pixelScale + xl);\n"
-            "   float4 bv = (float4)(y * pixelScaleY + yt);\n"
-            "   float4 ca = av;\n"
-            "   float4 cb = bv;\n"
+    if (smooth) {
+        return 
+    //        "#pragma OPENCL EXTENSION cl_khr_fp64 : enable"
+            "__kernel void iterate(__global float* A, const int width, float xl, float yt, float pixelScaleX, float pixelScaleY, int max) {"
+            "   int index = get_global_id(0);\n"
+            "   int x = index % width;"
+            "   int y = index / width;"
+            "   float a = x * pixelScaleX + xl;"
+            "   float b = y * pixelScaleY + yt;"
+            "   float ca = a;"
+            "   float cb = b;"
             ""
-            "   int4 counter = (int4) 1;"
-            "   float4 threshold = (float4) 16;"
-            "   int n = 0;\n"
-            "   while (n < max) {\n"
-            "       float4 aa = av * av;\n"
-            "       float4 bb = bv * bv;\n"
-            "       float4 ab = av * bv;\n"
-            "       av = aa - bb + ca;\n"
-            "       bv = 2 * ab + cb;\n"
-            "       counter += -(threshold > (aa + bb));\n"
-            "       if(all(threshold < (aa + bb))) break;\n"
-            "       //if (aa + bb > 16) break;\n"
-            "       n++;\n"
-            "   }\n\n"
-            "   A[index] = (float) counter[0];\n"
-            "   A[index + 1] = (float) counter[1];\n"
-            "   A[index + 2] = (float) counter[2];\n"
-            "   A[index + 3] = (float) counter[3];\n"
-    /*        "   A[index + 4] = (float) counter[4];\n"
-            "   A[index + 5] = (float) counter[5];\n"
-            "   A[index + 6] = (float) counter[6];\n"
-            "   A[index + 7] = (float) counter[7];\n"*/
-    //        "   A[get_global_id(0)] = 1;\n"
-            "}\n";
+            "   int n = 0;"
+            "   while (n < max - 1) {"
+            "       float aa = a * a;"
+            "       float bb = b * b;"
+            "       float ab = a * b;"
+            "       if (aa + bb > 16) break;"
+            "       a = aa - bb + ca;"
+            "       b = 2 * ab + cb;"
+            "       n++;"
+            "   }\n"
+                // N + 1 - log (log  |Z(N)|) / log 2
+            "   if (n >= max - 1)\n"
+            "       A[index] = max;\n"
+            "   else"
+            "       A[index] = ((float)n) + 1 - log(log(a * a + b * b) / 2) / log(2.0f);\n"
+//            "   A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);\n"
+    //        "   A[get_global_id(0)] = 5;"
+            "}";
     }
     else {
-
-        return 
+        return
     //        "#pragma OPENCL EXTENSION cl_khr_fp64 : enable"
             "__kernel void iterate(__global float* A, const int width, float xl, float yt, float pixelScaleX, float pixelScaleY, int max) {"
             "   int index = get_global_id(0);\n"
@@ -196,7 +189,7 @@ std::string ClGeneratorFloat::getKernelCode(void) const
             "   if (n >= max - 1)\n"
             "       A[index] = max;\n"
             "   else"
-            "       A[index] = ((float)n) + 1 - log(log(a * a + b * b) / 2) / log(2.0f);\n"
+            "       A[index] = ((float)n);\n"
 //            "   A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);\n"
     //        "   A[get_global_id(0)] = 5;"
             "}";
@@ -204,13 +197,13 @@ std::string ClGeneratorFloat::getKernelCode(void) const
 }
 
 
-ClGeneratorDouble::ClGeneratorDouble(cl::Device device) :
+ClGeneratorDouble::ClGeneratorDouble(cl::Device device, bool smooth) :
     ClGenerator{ device }
 {
     context = Context{ device };
     Program::Sources sources;
 
-    std::string kcode = this->getKernelCode();
+    std::string kcode = this->getKernelCode(smooth);
 
     sources.push_back({ kcode.c_str(), kcode.length() });
 
@@ -245,48 +238,81 @@ void ClGeneratorDouble::generate(const mnd::MandelInfo& info, float* data)
 }
 
 
-std::string ClGeneratorDouble::getKernelCode(void) const
+std::string ClGeneratorDouble::getKernelCode(bool smooth) const
 {
-    return 
-        "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
-        "__kernel void iterate(__global float* A, const int width, double xl, double yt, double pixelScaleX, double pixelScaleY, int max) {\n"
-        "   int index = get_global_id(0);\n"
-        "   int x = index % width;"
-        "   int y = index / width;"
-        "   double a = x * pixelScaleX + xl;"
-        "   double b = y * pixelScaleY + yt;"
-        "   double ca = a;"
-        "   double cb = b;"
-        ""
-        "   int n = 0;"
-        "   while (n < max - 1) {"
-        "       double aa = a * a;"
-        "       double bb = b * b;"
-        "       double ab = a * b;"
-        "       if (aa + bb > 16) break;"
-        "       a = aa - bb + ca;"
-        "       b = 2 * ab + cb;"
-        "       n++;"
-        "   }\n"
-        // N + 1 - log (log  |Z(N)|) / log 2
-        "   if (n >= max - 1)\n"
-        "       A[index] = max;\n"
-        "   else"
-        "       A[index] = ((float)n) + 1 - log(log(a * a + b * b) / 2) / log(2.0f);\n"
-        //            "   A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);\n"
-        //        "   A[get_global_id(0)] = 5;"
-        "}";
+    if (smooth) {
+        return
+            "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
+            "__kernel void iterate(__global float* A, const int width, double xl, double yt, double pixelScaleX, double pixelScaleY, int max) {\n"
+            "   int index = get_global_id(0);\n"
+            "   int x = index % width;"
+            "   int y = index / width;"
+            "   double a = x * pixelScaleX + xl;"
+            "   double b = y * pixelScaleY + yt;"
+            "   double ca = a;"
+            "   double cb = b;"
+            ""
+            "   int n = 0;"
+            "   while (n < max - 1) {"
+            "       double aa = a * a;"
+            "       double bb = b * b;"
+            "       double ab = a * b;"
+            "       if (aa + bb > 16) break;"
+            "       a = aa - bb + ca;"
+            "       b = 2 * ab + cb;"
+            "       n++;"
+            "   }\n"
+            // N + 1 - log (log  |Z(N)|) / log 2
+            "   if (n >= max - 1)\n"
+            "       A[index] = max;\n"
+            "   else"
+            "       A[index] = ((float)n) + 1 - log(log(a * a + b * b) / 2) / log(2.0f);\n"
+            //            "   A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);\n"
+            //        "   A[get_global_id(0)] = 5;"
+            "}";
+    }
+    else {
+        return
+            "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
+            "__kernel void iterate(__global float* A, const int width, double xl, double yt, double pixelScaleX, double pixelScaleY, int max) {\n"
+            "   int index = get_global_id(0);\n"
+            "   int x = index % width;"
+            "   int y = index / width;"
+            "   double a = x * pixelScaleX + xl;"
+            "   double b = y * pixelScaleY + yt;"
+            "   double ca = a;"
+            "   double cb = b;"
+            ""
+            "   int n = 0;"
+            "   while (n < max - 1) {"
+            "       double aa = a * a;"
+            "       double bb = b * b;"
+            "       double ab = a * b;"
+            "       if (aa + bb > 16) break;"
+            "       a = aa - bb + ca;"
+            "       b = 2 * ab + cb;"
+            "       n++;"
+            "   }\n"
+            // N + 1 - log (log  |Z(N)|) / log 2
+            "   if (n >= max - 1)\n"
+            "       A[index] = max;\n"
+            "   else"
+            "       A[index] = ((float)n);\n"
+            //            "   A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);\n"
+            //        "   A[get_global_id(0)] = 5;"
+            "}";
+    }
 }
 
 
 
-ClGenerator128::ClGenerator128(cl::Device device) :
+ClGenerator128::ClGenerator128(cl::Device device, bool smooth) :
     ClGenerator{ device }
 {
     context = Context{ device };
     Program::Sources sources;
 
-    std::string kcode = this->getKernelCode();
+    std::string kcode = this->getKernelCode(smooth);
 
     sources.push_back({ kcode.c_str(), kcode.length() });
 
@@ -324,7 +350,7 @@ void ClGenerator128::generate(const mnd::MandelInfo& info, float* data)
 #include <fstream>
 #include <streambuf>
 
-std::string ClGenerator128::getKernelCode(void) const
+std::string ClGenerator128::getKernelCode(bool smooth) const
 {
     //fprintf(stderr, "starting file read\n");
     std::ifstream t("mandel128.cl");

+ 56 - 29
libmandel/src/mandel.cpp

@@ -20,35 +20,40 @@ MandelContext mnd::initializeContext(void)
 
 MandelDevice::MandelDevice(void) :
     floatGenerator{ nullptr },
-    doubleGenerator{ nullptr }
+    doubleGenerator{ nullptr },
+    generator128{ nullptr },
+    floatGeneratorSmooth{ nullptr },
+    doubleGeneratorSmooth{ nullptr },
+    generator128Smooth{ nullptr }
+
 {
 }
 
 
-mnd::Generator* MandelDevice::getGeneratorFloat(void) const
+mnd::Generator* MandelDevice::getGeneratorFloat(bool smooth) const
 {
-    if (floatGenerator)
-        return floatGenerator.get();
+    if (smooth)
+        return floatGeneratorSmooth.get();
     else
-        return nullptr;
+        return floatGenerator.get();
 }
 
 
-mnd::Generator* MandelDevice::getGeneratorDouble(void) const
+mnd::Generator* MandelDevice::getGeneratorDouble(bool smooth) const
 {
-    if (doubleGenerator)
-        return doubleGenerator.get();
+    if (smooth)
+        return doubleGeneratorSmooth.get();
     else
-        return nullptr;
+        return doubleGenerator.get();
 }
 
 
-mnd::Generator* MandelDevice::getGenerator128(void) const
+mnd::Generator* MandelDevice::getGenerator128(bool smooth) const
 {
-    if (generator128)
-        return generator128.get();
+    if (smooth)
+        return generator128Smooth.get();
     else
-        return nullptr;
+        return generator128.get();
 }
 
 
@@ -57,41 +62,58 @@ MandelContext::MandelContext(void)
 
 #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) 
     if (cpuInfo.hasAvx()) {
-        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::X86_AVX>>();
-        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::X86_AVX>>();
+        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::X86_AVX, true, false>>();
+        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true, false>>();
+        cpuGeneratorFloatSmooth = std::make_unique<CpuGenerator<float, mnd::X86_AVX, true, true>>();
+        cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::X86_AVX, true, true>>();
     }
     else if (cpuInfo.hasSse2()) {
-        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::X86_SSE2>>();
-        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::X86_SSE2>>();
+        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::X86_SSE2, true, false>>();
+        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::X86_SSE2, true, false>>();
+        cpuGeneratorFloatSmooth = std::make_unique<CpuGenerator<float, mnd::X86_SSE2, true, true>>();
+        cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::X86_SSE2, true, true>>();
     }
     else
 #elif defined(__aarch64__)
     if (true) {
-        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::ARM_NEON>>();
-        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::ARM_NEON>>();
+        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::ARM_NEON, true, false>>();
+        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::ARM_NEON, true, false>>();
+        cpuGeneratorFloatSmooth = std::make_unique<CpuGenerator<float, mnd::ARM_NEON>>();
+        cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::ARM_NEON>>();
     }
     else
 #endif
     {
-        cpuGeneratorFloat = std::make_unique<CpuGenerator<float>>();
-        cpuGeneratorDouble = std::make_unique<CpuGenerator<double>>();
+        cpuGeneratorFloat = std::make_unique<CpuGenerator<float, mnd::NONE, true, false>>();
+        cpuGeneratorDouble = std::make_unique<CpuGenerator<double, mnd::NONE, true, false>>();
+        cpuGeneratorFloatSmooth = std::make_unique<CpuGenerator<float, mnd::NONE, true, true>>();
+        cpuGeneratorDoubleSmooth = std::make_unique<CpuGenerator<double, mnd::NONE, true, true>>();
     }
 
-    cpuGenerator128 = std::make_unique<CpuGenerator<Fixed128>>();
+    cpuGenerator128 = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true, false>>();
+    cpuGenerator128Smooth = std::make_unique<CpuGenerator<Fixed128>>();
     //cpuGeneratorFixedp = std::make_unique<CpuGenerator<fixed<1, 3>>>();
 
     devices = createDevices();
-    if (devices.empty() || true) {
+    if (devices.empty()) {
         adaptiveGenerator = std::make_unique<AdaptiveGenerator>(cpuGeneratorFloat.get(), cpuGeneratorDouble.get());
+        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(cpuGeneratorFloatSmooth.get(), cpuGeneratorDoubleSmooth.get());
     }
     else {
         auto& device1 = devices[0];
-        Generator* floatGenerator = device1.getGeneratorFloat();
-        Generator* doubleGenerator = device1.getGeneratorDouble();
+        Generator* floatGenerator = device1.getGeneratorFloat(false);
+        Generator* doubleGenerator = device1.getGeneratorDouble(false);
+        Generator* floatGeneratorSmooth = device1.getGeneratorFloat(true);
+        Generator* doubleGeneratorSmooth = device1.getGeneratorDouble(true);
         if (floatGenerator == nullptr)
             floatGenerator = cpuGeneratorFloat.get();
         if (doubleGenerator == nullptr)
             doubleGenerator = cpuGeneratorDouble.get();
+        if (floatGeneratorSmooth == nullptr)
+            floatGeneratorSmooth = cpuGeneratorFloatSmooth.get();
+        if (doubleGeneratorSmooth == nullptr)
+            doubleGeneratorSmooth = cpuGeneratorDoubleSmooth.get();
+        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(floatGeneratorSmooth, doubleGeneratorSmooth);
         adaptiveGenerator = std::make_unique<AdaptiveGenerator>(floatGenerator, doubleGenerator);
     }
 }
@@ -131,7 +153,8 @@ std::vector<MandelDevice> MandelContext::createDevices(void)
             md.name = device.getInfo<CL_DEVICE_NAME>();
             md.vendor = device.getInfo<CL_DEVICE_VENDOR>();
             try {
-                md.floatGenerator = std::make_unique<ClGeneratorFloat>(device);
+                md.floatGenerator = std::make_unique<ClGeneratorFloat>(device, false);
+                md.floatGeneratorSmooth = std::make_unique<ClGeneratorFloat>(device, true);
             }
             catch (const std::string& err) {
                 printf("err: %s", err.c_str());
@@ -139,7 +162,8 @@ std::vector<MandelDevice> MandelContext::createDevices(void)
 
             if (supportsDouble) {
                 try {
-                    md.doubleGenerator = std::make_unique<ClGeneratorDouble>(device);
+                    md.doubleGenerator = std::make_unique<ClGeneratorDouble>(device, false);
+                    md.doubleGeneratorSmooth = std::make_unique<ClGeneratorDouble>(device, true);
                 }
                 catch (const std::string& err) {
                 }
@@ -167,9 +191,12 @@ const std::string& MandelDevice::getName(void) const
 }
 
 
-Generator& MandelContext::getDefaultGenerator(void)
+Generator& MandelContext::getDefaultGenerator(bool smooth)
 {
-    return *adaptiveGenerator;
+    if (smooth)
+        return *adaptiveGeneratorSmooth;
+    else
+        return *adaptiveGenerator;
 }