| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 | #pragma once#include <QGLWidget>#include <QOpenGLWidget>#include <QThreadPool>#include <QMouseEvent>#include <QOpenGLContext>#include <QOpenGLFunctions>#include <QMutex>//#include <qopengl.h>//#include <qopenglfunctions.h>//#include <qopenglcontext.h>#include "Bitmap.h"#include "Gradient.h"#include <Mandel.h>#include <atomic>#include <tuple>#include <deque>#include <chrono>#include <unordered_map>#include <unordered_set>using GridIndex = long long;Q_DECLARE_METATYPE(GridIndex)class Texture{    GLuint id;public:    Texture(const Bitmap<RGBColor>& pict, GLint param = GL_LINEAR);    ~Texture(void);    Texture(const Texture& other) = delete;    Texture& operator=(const Texture& other) = delete;    Texture(Texture&& other);    Texture& operator=(Texture&& other);private:    void bind(void) const;public:    inline GLuint getId(void) const { return id; }    void drawRect(float x, float y, float width, float height);};class CellImage{public:    virtual ~CellImage(void);    virtual void drawRect(float x, float y, float width, float height) = 0;    virtual std::shared_ptr<CellImage> clip(short i, short j) = 0;    virtual int getRecalcPriority(void) const = 0;};class TextureClip : public CellImage{    std::shared_ptr<Texture> texture;    float tx, ty, tw, th;public:    inline TextureClip(std::shared_ptr<Texture> tex) :        texture{ std::move(tex) },        tx{ 0 }, ty{ 0 }, tw{ 1 }, th{ 1 }    {}    virtual ~TextureClip(void);    void drawRect(float x, float y, float width, float height);    TextureClip clip(float x, float y, float w, float h);    std::shared_ptr<CellImage> clip(short i, short j);    int getRecalcPriority(void) const;};class QuadImage : public CellImage{    std::shared_ptr<CellImage> cells[2][2];public:    inline QuadImage(std::shared_ptr<CellImage> i00,                     std::shared_ptr<CellImage> i01,                     std::shared_ptr<CellImage> i10,                     std::shared_ptr<CellImage> i11) :        cells{ { std::move(i00), std::move(i01) }, { std::move(i10), std::move(i11) } }    {}    virtual ~QuadImage(void);    void drawRect(float x, float y, float width, float height);    std::shared_ptr<CellImage> clip(short i, short j);    int getRecalcPriority(void) const;};struct PairHash {    template <typename T1, typename T2>    std::size_t operator () (const std::pair<T1, T2>& p) const {        auto h1 = std::hash<T1>{}(p.first);        auto h2 = std::hash<T2>{}(p.second);        return (h1 ^ 234579245) * 23452354 + h2;    }};struct TripleHash {    template <typename T1, typename T2, typename T3>    std::size_t operator () (const std::tuple<T1, T2, T3>& p) const {        auto h1 = std::hash<T1>{}(std::get<0>(p));        auto h2 = std::hash<T2>{}(std::get<1>(p));        auto h3 = std::hash<T3>{}(std::get<2>(p));        return (((h1 ^ 234579245) * 23452357 + h2) ^ 2345244345) * 23421 + h3;    }};struct GridElement{    bool enoughResolution;    std::shared_ptr<CellImage> img;    inline GridElement(bool enoughResolution, std::shared_ptr<CellImage> img) :        enoughResolution{ enoughResolution },        img{ std::move(img) }    {}};class MandelV;class TexGrid{public:    MandelV& owner;    int level;    double dpp;    std::unordered_map<std::pair<GridIndex, GridIndex>, std::unique_ptr<GridElement>, PairHash> cells;public:    //inline TexGrid(MandelV& owner) : level{ 1.0 }, owner{ owner } {}    TexGrid(MandelV& owner, int level);    std::pair<GridIndex, GridIndex> getCellIndices(double x, double y);    std::pair<double, double> getPositions(GridIndex i, GridIndex j);    GridElement* getCell(GridIndex i, GridIndex j);    void setCell(GridIndex i, GridIndex j, std::unique_ptr<GridElement> tex);    inline size_t countAllocatedCells(void) const { return cells.size(); }    void clearCells(void);};class Job : public QObject, public QRunnable{    Q_OBJECTpublic:    mnd::MandelContext& mndContext;    Gradient& gradient;    int maxIter;    TexGrid* grid;    int level;    GridIndex i, j;    inline Job(mnd::MandelContext& mndContext,               Gradient& gradient,               int maxIter,               TexGrid* grid,               int level, GridIndex i, GridIndex j) :        mndContext{ mndContext },        gradient{ gradient },        maxIter{ maxIter },        grid{ grid },        level{ level },        i{ i }, j{ j }    {}    void run() override;signals:    void done(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp);};class Calcer : public QObject{    Q_OBJECT    /// tuple contains level, i, j of the job    std::unordered_map<std::tuple<int, GridIndex, GridIndex>, Job*, TripleHash> jobs;    QMutex jobsMutex;    mnd::MandelContext& mndContext;    std::unique_ptr<QThreadPool> threadPool;    Gradient& gradient;    int maxIter;    int currentLevel;public:    inline Calcer(mnd::MandelContext& mc, Gradient& gradient, int maxIter) :        jobsMutex{ QMutex::Recursive },        mndContext{ mc },        threadPool{ std::make_unique<QThreadPool>() },        gradient{ gradient },        maxIter{ maxIter }    {    }    void setMaxIter(int maxIter);    void clearAll(void);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);signals:    void done(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp);};class MandelV : public QObject{    Q_OBJECTpublic:    std::unique_ptr<Texture> empty;    // 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;    Calcer calcer;    Gradient& gradient;    int maxIter;    int width;    int height;public:    static const int chunkSize = 256;    MandelV(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter);    int getLevel(double dpp);    double getDpp(int level);    TexGrid& getGrid(int level);    inline int getMaxIter(void) const { return this->maxIter; }    void setMaxIter(int maxIter);    void clear(void);    void garbageCollect(int level, GridIndex i, GridIndex j);    GridElement* searchAbove(int level, GridIndex i, GridIndex j, int recursionLevel);    GridElement* searchUnder(int level, GridIndex i, GridIndex j, int recursionLevel);    void paint(const mnd::MandelViewport& mvp);public slots:    void cellReady(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp);signals:    void redrawRequested(void);};class MandelWidget : public QOpenGLWidget{    Q_OBJECTprivate:    mnd::MandelContext& mndContext;    Gradient gradient;    bool initialized = false;    int maxIterations = 2000;    volatile bool rubberbanding = false;    QRectF rubberband;    volatile bool dragging = false;    int dragX, dragY;    mnd::MandelViewport currentViewport;    mnd::MandelViewport targetViewport;    std::chrono::time_point<std::chrono::high_resolution_clock> lastAnimUpdate;    std::unique_ptr<MandelV> v;public:    MandelWidget(mnd::MandelContext& ctxt, QWidget* parent = nullptr);    ~MandelWidget(void) override;    inline const Gradient& getGradient(void) const { return gradient; }    void initializeGL(void) override;    void resizeGL(int w, int h) override;    void paintGL() override;private:    void updateAnimations(void);    void drawRubberband(void);public:    void zoom(float scale, float x = 0.5f, float y = 0.5f);    void setMaxIterations(int maxIter);    //void redraw();    void requestRecalc(void);    void resizeEvent(QResizeEvent* re) override;    void mousePressEvent(QMouseEvent* me) override;    void mouseMoveEvent(QMouseEvent* me) override;    void mouseReleaseEvent(QMouseEvent* me) override;    void wheelEvent(QWheelEvent * we) override;    inline const mnd::MandelViewport& getViewport(void) const { return targetViewport; }signals:    void needsUpdate(const mnd::MandelInfo vp);public slots:    //void viewUpdated(Bitmap<RGBColor>* bitmap);};
 |