Browse Source

restructuring

Nicolas Winkler 5 năm trước cách đây
mục cha
commit
f6f0052adc

+ 43 - 85
Almond.cpp

@@ -17,23 +17,24 @@ Almond::Almond(QWidget* parent) :
     mandelContext{ mnd::initializeContext() }
 {
     ui.setupUi(this);
-    mw = std::make_unique<MandelWidget>(mandelContext,
-                                        &mandelContext.getDefaultGenerator(),
-                                        ui.centralWidget);
-    etvw = new EscapeTimeVisualWidget(this);
+    //mw = std::make_unique<MandelWidget>(mandelContext,
+    //                                    &mandelContext.getDefaultGenerator(),
+    //                                    ui.centralWidget);
+    fractalWidget = new FractalZoomWidget(this);
+    fractalWidget->setGenerator(&mandelContext.getDefaultGenerator());
     customGeneratorDialog = std::make_unique<CustomGenerator>(mandelContext);
     customGenerator = nullptr;
     customViewSave = mnd::MandelViewport::centerView();
 
     on_maxIterations_editingFinished();
-    mw->setSmoothColoring(ui.smooth->isChecked());
+    // TODO update mw->setSmoothColoring(ui.smooth->isChecked());
 
     currentView = MANDELBROT;
     mandelGenerator = &mandelContext.getDefaultGenerator();
-    mandelViewSave = mw->getViewport();
+    // TODO update mandelViewSave = mw->getViewport();
 
-    QObject::connect(mw.get(), &MandelWidget::pointSelected, this, &Almond::pointSelected);
-    ui.mandel_container->addWidget(etvw);
+    //QObject::connect(mw.get(), &MandelWidget::pointSelected, this, &Almond::pointSelected);
+    ui.mandel_container->addWidget(fractalWidget);
     //ui.mandel_container->addWidget(mw.get());
     ui.maxIterations->setValidator(new QIntValidator(1, 1000000000, this));
 
@@ -143,33 +144,35 @@ void Almond::imageExportOk(void)
 {
     mnd::MandelInfo mi;
     mi.maxIter = eim->getMaxIterations();
-    mi.view = mw->getViewport();
+    mi.view = mnd::MandelViewport{};// mw->getViewport(); // TODO update
     mi.bWidth = eim->getWidth();
     mi.bHeight = eim->getHeight();
     mi.view.adjustAspectRatio(mi.bWidth, mi.bHeight);
-    mi.smooth = mw->getSmoothColoring();
-    if (currentView == JULIA) {
+    mi.smooth = true; // TODO update
+    /*if (currentView == JULIA) {
         mi.julia = mw->getMandelInfo().julia;
         mi.juliaX = mw->getJuliaX();
         mi.juliaY = mw->getJuliaY();
-    }
+    }*/
 
-    mnd::MandelGenerator* currentGenerator = mw->getGenerator();
+    mnd::MandelGenerator* currentGenerator = nullptr;// mw->getGenerator();// TODO update
     mnd::MandelGenerator& g = currentGenerator ? *currentGenerator : mandelContext.getDefaultGenerator();
 
     alm::ImageExportInfo iei;
     iei.drawInfo = mi;
     iei.generator = &g;
-    iei.gradient = mw->getGradient();
+    iei.gradient = Gradient::defaultGradient(); // mw->getGradient();// TODO update
     iei.path = eim->getPath().toStdString();
     iei.options.jpegQuality = 95;
     submitBackgroundTask(new ImageExportTask(iei, [this] () { return stoppingBackgroundTasks; }));
+    
     amw->showMainMenu();
 }
 
 
 void Almond::videoExportOk(void)
 {
+    /*
     ExportVideoInfo evi = evm->getInfo();
     evi.gradient = mw->getGradient();
     evi.mi.smooth = mw->getSmoothColoring();
@@ -190,6 +193,7 @@ void Almond::videoExportOk(void)
         submitBackgroundTask(new VideoExportTask(std::move(mvg), g));
         amw->showMainMenu();
     }
+    */
 }
 
 
@@ -221,13 +225,14 @@ void Almond::gradientEditOk(void)
     std::for_each(np.begin(), np.end(), [](auto& x) { x.second *= 300; });
 
     Gradient g{ np, true };
-    mw->setGradient(std::move(g));
+    //mw->setGradient(std::move(g)); // TODO update
     amw->showMainMenu();
 }
 
 
 void Almond::toggleFullscreen(void)
 {
+    /*
     if (fullscreenMode) {
         auto* m = this->takeCentralWidget();
         ui.mandel_container->addWidget(m);
@@ -241,6 +246,7 @@ void Almond::toggleFullscreen(void)
         emit this->showFullScreen();
         fullscreenMode = true;
     }
+    */
 }
 
 
@@ -286,13 +292,13 @@ void Almond::backgroundTaskProgress(float percentage)
 
 void Almond::on_zoom_out_clicked()
 {
-    mw->zoom(2);
+    // TODO update mw->zoom(2);
 }
 
 
 void Almond::on_zoom_in_clicked()
 {
-    mw->zoom(0.5);
+    // TODO update mw->zoom(0.5);
 }
 
 
@@ -300,13 +306,14 @@ void Almond::on_maxIterations_editingFinished()
 {
     QString text = ui.maxIterations->text();
     int maxIter = text.toInt();
-    mw->setMaxIterations(maxIter);
+    // TODO update mw->setMaxIterations(maxIter);
 }
 
 
 void Almond::on_chooseGradient_clicked()
 {
-    const auto& gradient = mw->getGradient();
+    /*
+    const auto& gradient = mw->getGradient(); // TODO update
     auto points = gradient.getPoints();
     std::for_each(points.begin(), points.end(), [](auto& x) { x.second /= 300; });
 
@@ -316,7 +323,7 @@ void Almond::on_chooseGradient_clicked()
         auto& [col, pos] = qp;
         return { pos, QColor{ (col.r), (col.g), (col.b) } };
     });
-    this->gradientMenu->setGradient(std::move(np));
+    this->gradientMenu->setGradient(std::move(np));*/
     emit this->amw->showSubMenu(2);
     //gcd.exec();
     //auto gradient = gcd.getGradient();
@@ -327,6 +334,8 @@ void Almond::on_chooseGradient_clicked()
 
 void Almond::on_exportVideo_clicked()
 {
+    // TODO update
+    /*
     evm->setEndViewport(mw->getViewport());
     emit this->amw->showSubMenu(1);
     return;
@@ -345,26 +354,13 @@ void Almond::on_exportVideo_clicked()
         mnd::MandelGenerator& g = *mw->getGenerator();
         submitBackgroundTask(new VideoExportTask(std::move(mvg), g));
         //if (exportVideo(evi)) {
-
-        //Video
-        /*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.getDefaultGenerator();
-        auto fmap = Bitmap<float>(mi.bWidth, mi.bHeight);
-        g.generate(mi, fmap.pixels.get());
-        auto bitmap = fmap.map<RGBColor>([](float i) { return i < 0 ? RGBColor{ 0,0,0 } : RGBColor{ uint8_t(cos(i * 0.015f) * 127 + 127), uint8_t(sin(i * 0.01f) * 127 + 127), uint8_t(i) }; });//uint8_t(::sin(i * 0.01f) * 100 + 100), uint8_t(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_smooth_stateChanged(int checked)
 {
-    this->mw->setSmoothColoring(checked != Qt::Unchecked);
+    // TODO update this->mw->setSmoothColoring(checked != Qt::Unchecked);
 }
 
 
@@ -372,66 +368,23 @@ void Almond::on_exportImage_clicked()
 {
     this->amw->showSubMenu(0);
     return;
-
-    ExportImageDialog dialog(this);
-    dialog.setMaxIterations(mw->getMaxIterations());
-    //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);
-        mi.smooth = mw->getSmoothColoring();
-        if (currentView == JULIA) {
-            mi.julia = mw->getMandelInfo().julia;
-            mi.juliaX = mw->getJuliaX();
-            mi.juliaY = mw->getJuliaY();
-        }
-        mnd::MandelGenerator* currentGenerator = mw->getGenerator();
-        mnd::MandelGenerator& g = currentGenerator ? *currentGenerator : mandelContext.getDefaultGenerator();
-
-        alm::ImageExportInfo iei;
-        iei.drawInfo = mi;
-        iei.generator = &g;
-        iei.gradient = mw->getGradient();
-        iei.path = dialog.getPath().toStdString();
-        iei.options.jpegQuality = 95;
-        submitBackgroundTask(new ImageExportTask(iei, [this] () { return stoppingBackgroundTasks; }));
-
-        /*auto exprt = [iei, path = dialog.getPath().toStdString()]() {
-            alm::exportPng(path, iei);
-        };
-
-        submitBackgroundTask();*/
-        
-        /*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(reinterpret_cast<unsigned char*>(bitmap.pixels.get()), bitmap.width, bitmap.height, bitmap.width * 3, QImage::Format_RGB888);
-        img.save(dialog.getPath());*/
-    }
 }
 
 
 void Almond::on_resetZoom_clicked()
 {
     if (currentView == MANDELBROT) {
-        mw->setViewport(mnd::MandelViewport::standardView());
+        // TODO update mw->setViewport(mnd::MandelViewport::standardView());
     }
     else {
-        mw->setViewport(mnd::MandelViewport::centerView());
+        // TODO update mw->setViewport(mnd::MandelViewport::centerView());
     }
 }
 
 
 void Almond::on_displayInfo_stateChanged(int checked)
 {
-    this->mw->setDisplayInfo(checked != Qt::Unchecked);
+    // TODO update this->mw->setDisplayInfo(checked != Qt::Unchecked);
 }
 
 
@@ -456,7 +409,7 @@ void Almond::on_chooseGenerator_clicked()
             customGenerator = gen.get();
         }
         currentGenerator = gen.get();
-        this->mw->setGenerator(currentGenerator);
+        // TODO update this->mw->setGenerator(currentGenerator);
         adjustedGenerators.push_back(std::move(gen));
     }
     else {
@@ -472,10 +425,12 @@ void Almond::pointSelected(mnd::Real x, mnd::Real y)
 {
     if (currentView != JULIA) {
         saveView();
+        // TODO update
+        /*
         this->mw->setViewport(mnd::MandelViewport::centerView());
         this->mw->setJuliaPos(x, y);
         this->mw->getMandelInfo().julia = true;
-        this->mw->clearAll();
+        this->mw->clearAll();*/
     }
     currentView = JULIA;
 }
@@ -490,14 +445,16 @@ void Almond::on_wMandel_clicked()
 void Almond::saveView()
 {
     if (currentView == MANDELBROT)
-        mandelViewSave = mw->getViewport();
+        ; // TODO update mandelViewSave = mw->getViewport();
     else if (currentView == CUSTOM)
-        customViewSave = mw->getViewport();
+        ; // TODO update customViewSave = mw->getViewport();
 }
 
 
 void Almond::setViewType(ViewType v)
 {
+    // TODO update
+    /*
     saveView();
     if (v == MANDELBROT) {
         currentGenerator = mandelGenerator;
@@ -536,6 +493,7 @@ void Almond::setViewType(ViewType v)
             emit this->mw->selectPoint();
         }
     }
+    */
 }
 
 

+ 2 - 3
Almond.h

@@ -13,7 +13,7 @@
 #include "choosegenerators.h"
 #include "customgenerator.h"
 
-#include "EscapeTimeVisualWidget.h"
+#include "FractalZoomWidget.h"
 
 #include "AlmondMenuWidget.h"
 #include "ExportImageMenu.h"
@@ -54,8 +54,7 @@ private:
     bool fullscreenMode = false;
     QWidget* cw;
 public:
-    std::unique_ptr<MandelWidget> mw;
-    EscapeTimeVisualWidget* etvw;
+    FractalZoomWidget* fractalWidget;
 private:
     //std::unique_ptr<BenchmarkDialog> benchmarkDialog;
     std::unique_ptr<CustomGenerator> customGeneratorDialog;

+ 3 - 3
EscapeTimeVisualWidget.h

@@ -34,9 +34,9 @@ class EscapeTimeVisualWidget :
 public:
     EscapeTimeVisualWidget(QWidget* parent = nullptr);
 
-    void initializeGL(void) override;
-    void resizeGL(int w, int h) override;
-    void paintGL(void) override;
+    virtual void initializeGL(void) override;
+    virtual void resizeGL(int w, int h) override;
+    virtual void paintGL(void) override;
 };
 
 #endif // ESCAPETIMEVISUALWIDGET_H

+ 49 - 4
FractalWidgetUtils.cpp

@@ -1,4 +1,6 @@
 #include "FractalWidgetUtils.h"
+#include "FractalZoomWidget.h"
+
 
 
 CellImage::~CellImage(void)
@@ -61,13 +63,11 @@ QuadImage::~QuadImage(void)
 }
 
 
-void QuadImage::drawRect(QOpenGLShaderProgram* program,
-        float x, float y, float width, float height)
+void QuadImage::drawRect(float x, float y, float width, float height)
 {
     for (int i = 0; i < 2; i++) {
         for (int j = 0; j < 2; j++) {
-            this->cells[i][j]->drawRect(program,
-                                        x + i * 0.5f * width,
+            this->cells[i][j]->drawRect(x + i * 0.5f * width,
                                         y + j * 0.5f * height,
                                         width * 0.5f,
                                         height * 0.5f);
@@ -86,3 +86,48 @@ int QuadImage::getRecalcPriority() const
 {
     return 1;
 }
+
+
+void CalcJob::run(void)
+{
+    auto [absX, absY] = grid->getPositions(i, j);
+    mnd::Real gw = grid->dpp * FractalZoomWidget::chunkSize;
+
+    Bitmap<float> f{ FractalZoomWidget::chunkSize, FractalZoomWidget::chunkSize };
+    mnd::MandelInfo mi = owner.getMandelInfo();
+    mi.view.x = absX;
+    mi.view.y = absY;
+    mi.view.width = mi.view.height = gw;
+    mi.bWidth = mi.bHeight = FractalZoomWidget::chunkSize;
+    try {
+        generator->generate(mi, f.pixels.get());
+        emit done(new Bitmap<float>(std::move(f)));
+    }
+    catch(std::exception& ex) {
+        emit failed(ex.what());
+    }
+    catch(...) {
+        emit failed(tr("unknown error"));
+    }
+}
+
+
+size_t IndexPairHash::operator()(const std::pair<GridIndex, GridIndex>& p) const
+{
+    const auto& [a, b] = p;
+    size_t truncA = static_cast<size_t>(a);
+    size_t truncB = static_cast<size_t>(b);
+    boost::hash_combine(truncA, truncB);
+    return truncA;
+}
+
+
+size_t IndexTripleHash::operator()(const std::tuple<int, GridIndex, GridIndex>& p) const
+{
+    const auto& [i, a, b] = p;
+    size_t truncA = static_cast<size_t>(a);
+    size_t truncB = static_cast<size_t>(b);
+    boost::hash_combine(truncA, truncB);
+    boost::hash_combine(truncA, i);
+    return truncA;
+}

+ 54 - 1
FractalWidgetUtils.h

@@ -1,10 +1,20 @@
 #ifndef FRACTALWIDGETUTILS_H
 #define FRACTALWIDGETUTILS_H
 
-#include "Mandel.h"
 #include "EscapeTimeVisualWidget.h"
+#include "Mandel.h"
+#include "Bitmap.h"
 #include <unordered_map>
 #include <QMetaType>
+#include <QObject>
+#include <QRunnable>
+
+#include <utility>
+
+
+class SliceGrid;
+class FractalZoomWidget;
+
 
 using GridIndex = mnd::Integer;
 Q_DECLARE_METATYPE(GridIndex)
@@ -82,4 +92,47 @@ struct GridElement
     {}
 };
 
+
+class CalcJob : public QObject, public QRunnable
+{
+    Q_OBJECT
+public:
+    FractalZoomWidget& owner;
+    mnd::MandelGenerator* generator;
+    SliceGrid* grid;
+    int level;
+    GridIndex i, j;
+    long calcState = 0;
+
+    inline CalcJob(FractalZoomWidget& owner,
+        mnd::MandelGenerator* generator,
+        SliceGrid* grid, int level,
+        GridIndex i, GridIndex j,
+        long calcState) :
+        owner{ owner },
+        generator{ generator },
+        grid{ grid },
+        level{ level },
+        i{ i }, j{ j },
+        calcState{ calcState }
+    {}
+
+    void run() override;
+signals:
+    void done(Bitmap<float>* bmp);
+    void failed(QString err);
+};
+
+
+struct IndexPairHash
+{
+    size_t operator()(const std::pair<GridIndex, GridIndex>& p) const;
+};
+
+
+struct IndexTripleHash
+{
+    size_t operator()(const std::tuple<int, GridIndex, GridIndex>& p) const;
+};
+
 #endif // FRACTALWIDGETUTILS_H

+ 136 - 6
FractalZoomWidget.cpp

@@ -1,5 +1,7 @@
 #include "FractalZoomWidget.h"
 
+#include <QOpenGLContext>
+#include <QOpenGLFunctions>
 
 SliceGrid::SliceGrid(FractalZoomWidget& owner, int level) :
     owner{ owner },
@@ -11,13 +13,19 @@ SliceGrid::SliceGrid(FractalZoomWidget& owner, int level) :
 
 std::pair<GridIndex, GridIndex> SliceGrid::getCellIndices(mnd::Real x, mnd::Real y)
 {
-    return { GridIndex(mnd::floor(x / dpp / FractalZoomWidget::chunkSize)), GridIndex(mnd::floor(y / dpp / MandelView::chunkSize)) };
+    return {
+        GridIndex(mnd::floor(x / dpp / FractalZoomWidget::chunkSize)),
+        GridIndex(mnd::floor(y / dpp / FractalZoomWidget::chunkSize))
+    };
 }
 
 
 std::pair<mnd::Real, mnd::Real> SliceGrid::getPositions(GridIndex x, GridIndex y)
 {
-    return { mnd::Real(x) * dpp * FractalZoomWidget::chunkSize, mnd::Real(y) * dpp * MandelView::chunkSize };
+    return {
+        mnd::Real(x) * dpp * FractalZoomWidget::chunkSize,
+        mnd::Real(y) * dpp * FractalZoomWidget::chunkSize
+    };
 }
 
 
@@ -33,19 +41,19 @@ GridElement* SliceGrid::getCell(GridIndex i, GridIndex j)
 }
 
 
-void TexGrid::setCell(GridIndex i, GridIndex j, std::unique_ptr<GridElement> tex)
+void SliceGrid::setCell(GridIndex i, GridIndex j, std::unique_ptr<GridElement> tex)
 {
     cells[{i, j}] = std::move(tex);
 }
 
 
-void TexGrid::clearCells(void)
+void SliceGrid::clearCells(void)
 {
     cells.clear();
 }
 
 
-void TexGrid::clearUncleanCells(void)
+void SliceGrid::clearUncleanCells(void)
 {
     for (auto it = cells.begin(); it != cells.end();) {
         if (it->second->img->getRecalcPriority() > 1)
@@ -55,10 +63,132 @@ void TexGrid::clearUncleanCells(void)
 }
 
 
+Calcer::Calcer(FractalZoomWidget& owner) :
+    jobsMutex{ QMutex::Recursive },
+    threadPool{ new QThreadPool(this) },
+    owner{ owner }
+{
+    threadPool->setMaxThreadCount(1);
+}
+
+void Calcer::clearAll(void)
+{
+    this->threadPool->clear();
+}
+
+
+void Calcer::calc(SliceGrid& grid, int level, GridIndex i, GridIndex j, int priority)
+{
+    jobsMutex.lock();
+    if (jobs.find({ level, i, j }) == jobs.end()) {
+        CalcJob* job = new CalcJob(owner, owner.getGenerator(), &grid, level, i, j, calcState);
+        connect(job, &CalcJob::done, this, &Calcer::redirect);
+        connect(job, &CalcJob::failed, this, &Calcer::jobFailed);
+        connect(job, &QObject::destroyed, this, [this, level, i, j] () { this->notFinished(level, i, j); });
+        jobs.emplace(std::tuple{ level, i, j }, job);
+        threadPool->start(job, priority);
+    }
+    jobsMutex.unlock();
+}
+
+
+void Calcer::setCurrentLevel(int level)
+{
+    if (this->currentLevel != level) {
+        this->currentLevel = level;
+        std::vector<QRunnable*> toCancel;
+        jobsMutex.lock();
+        for (auto&[tup, job] : jobs) {
+            auto& [level, i, j] = tup;
+            if(level != currentLevel) {
+                toCancel.push_back(job);
+            }
+        }
+        jobsMutex.unlock();
+        for (auto* job : toCancel) {
+            if (threadPool->tryTake(job)) {
+                delete job;
+            }
+        }
+    }
+}
+
+
+void Calcer::notFinished(int level, GridIndex i, GridIndex j)
+{
+    jobsMutex.lock();
+    jobs.erase({ level, i, j });
+    jobsMutex.unlock();
+}
+
+
+void Calcer::jobFailed(void)
+{
+
+}
+
+
+void Calcer::redirect(Bitmap<float>* bmp)
+{
+    QObject* s = sender();
+    if (CalcJob* cj = qobject_cast<CalcJob*>(s)) {
+        int level = cj->level;
+        GridIndex i = cj->i;
+        GridIndex j = cj->j;
+        jobsMutex.lock();
+        jobs.erase({ level, i, j });
+        jobsMutex.unlock();
+        if (this->calcState == calcState) {
+            emit done(level, i, j, bmp);
+        }
+        else {
+            delete bmp;
+        }
+    }
+    else {
+        delete bmp;
+    }
+}
+
+
 FractalZoomWidget::FractalZoomWidget(QWidget* parent) :
-    EscapeTimeVisualWidget{ parent }
+    EscapeTimeVisualWidget{ parent },
+    calcer{ *this }
+{
+}
+
+
+mnd::Real FractalZoomWidget::getDpp(int level)
+{
+    return mnd::pow(mnd::Real(2), mnd::Real(level)) * chunkSize;
+}
+
+
+const mnd::MandelInfo& FractalZoomWidget::getMandelInfo(void) const
 {
+    return mandelInfo;
 }
 
 
+void FractalZoomWidget::setGenerator(mnd::MandelGenerator* gen)
+{
+    this->generator = gen;
+}
 
+
+mnd::MandelGenerator* FractalZoomWidget::getGenerator(void) const
+{
+    return generator;
+}
+
+
+void FractalZoomWidget::paintGL(void)
+{
+    ETVImage etvi{ *this };
+
+    auto& gl = *this->context()->functions();
+    gl.glClearColor(0.0, 0.2, 0.0, 1.0);
+    gl.glClear(GL_COLOR_BUFFER_BIT);
+
+    etvi.draw(100, 100, 700, 700);
+}

+ 48 - 0
FractalZoomWidget.h

@@ -3,10 +3,15 @@
 
 #include "EscapeTimeVisualWidget.h"
 #include "FractalWidgetUtils.h"
+#include "Bitmap.h"
+
+#include <QThreadPool>
+#include <QMutex>
 
 class FractalZoomWidget;
 
 
+
 ///
 /// \brief represents a grid of images at a certain depth
 ///        in the fractal.
@@ -32,17 +37,60 @@ public:
 };
 
 
+class Calcer : public QObject
+{
+    Q_OBJECT
+
+    /// tuple contains level, i, j of the job
+    std::unordered_map<std::tuple<int, GridIndex, GridIndex>, CalcJob*, IndexTripleHash> jobs;
+    QMutex jobsMutex;
+    QThreadPool* threadPool;
+    FractalZoomWidget& owner;
+    int currentLevel;
+
+    volatile unsigned int calcState = 0;
+public:
+    Calcer(FractalZoomWidget& owner);
+    void clearAll(void);
+
+    inline void changeState(void) { calcState++; }
+
+public slots:
+    void calc(SliceGrid& grid, int level, GridIndex i, GridIndex j, int priority);
+    void setCurrentLevel(int level);
+    void notFinished(int level, GridIndex i, GridIndex j);
+    void jobFailed(void);
+    void redirect(Bitmap<float>* bmp);
+signals:
+    void done(int level, GridIndex i, GridIndex j, Bitmap<float>* bmp);
+};
+
+
 class FractalZoomWidget :
     public EscapeTimeVisualWidget
 {
     Q_OBJECT
 
+    // a grid should not be deleted once constructed.
+    // to free up memory one can call SliceGrid::clearCells()
+    std::unordered_map<int, SliceGrid> levels;
     mnd::MandelGenerator* generator;
+    Calcer calcer;
+
+    mnd::MandelInfo mandelInfo;
 
 public:
     static const int chunkSize = 256;
 
     FractalZoomWidget(QWidget* parent = nullptr);
+
+    mnd::Real getDpp(int level);
+    const mnd::MandelInfo& getMandelInfo(void) const;
+
+    void setGenerator(mnd::MandelGenerator*);
+    mnd::MandelGenerator* getGenerator(void) const;
+
+    void paintGL(void) override;
 };
 
 #endif // FRACTALZOOMWIDGET_H

+ 5 - 0
MandelWidget.cpp

@@ -1,3 +1,5 @@
+#if 0
+
 #include "MandelWidget.h"
 #include <cmath>
 #include <sstream>
@@ -621,6 +623,7 @@ void MandelView::paint(const mnd::MandelViewport& mvp)
     }
 }
 
+
 void MandelView::cellReady(int level, GridIndex i, GridIndex j, Bitmap<float>* bmp)
 {
     auto& gl = *QOpenGLContext::currentContext()->functions();
@@ -1166,3 +1169,5 @@ void MandelWidget::wheelEvent(QWheelEvent* we)
         emit repaint();
     }
 }*/
+
+#endif

+ 2 - 0
MandelWidget.h

@@ -1,4 +1,5 @@
 #pragma once
+#if 0
 
 #include <QGLWidget>
 #include <QOpenGLWidget>
@@ -403,3 +404,4 @@ signals:
     void pointSelected(mnd::Real x, mnd::Real y);
 };
 
+#endif

+ 4 - 2
exportdialogs.cpp

@@ -146,6 +146,7 @@ const ExportVideoInfo& ExportVideoDialog::getExportVideoInfo(void) const
 
 void ExportVideoDialog::on_buttonBox_accepted()
 {
+    /*
     if (evd.savePath->text() == "") {
         QMessageBox* msgBox = new QMessageBox;
         msgBox->setText("Please specify a path.");
@@ -176,14 +177,15 @@ void ExportVideoDialog::on_buttonBox_accepted()
         evd.endW->text().toDouble(),
         evd.endH->text().toDouble(),
     };*/
-
+    /*
     evi.start.adjustAspectRatio(evi.mi.bWidth, evi.mi.bHeight);
     evi.end.adjustAspectRatio(evi.mi.bWidth, evi.mi.bHeight);
     evi.gradient = almond->mw->getGradient();
-
+    */
     //}
 }
 
+
 void ExportVideoDialog::on_pushButton_clicked()
 {
     QString saveAs = QFileDialog::getSaveFileName(this,

+ 1 - 1
libmandel/include/Types.h

@@ -217,7 +217,7 @@ namespace mnd
     template<>
     inline Fixed64 convert<Fixed64, Real>(const Real& x)
     {
-        return static_cast<int64_t>(x * 0xFFFFFFFFFFFFLL);
+        return Fixed64{ static_cast<int64_t>(x * 0xFFFFFFFFFFFFLL), true };
     }
 
     template<>