#ifndef _core_h_
#define _core_h_
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <iostream>
#include <map>
#include <mutex>
#include <thread>
#include <vector>

#include "glad.h"
class QWindow;
namespace GL {
    inline QSurfaceFormat surface_format() {
        QSurfaceFormat format = QSurfaceFormat::defaultFormat();
        format.setMajorVersion(3);
        format.setMinorVersion(2);
        //format.setProfile(QSurfaceFormat::CompatibilityProfile);
        format.setProfile(QSurfaceFormat::CoreProfile);
        return format;
    }

    inline QOpenGLContext* context_init(QSurface* w, const QSurfaceFormat& format) {
        auto context = new QOpenGLContext();
        context->setFormat(format);
        context->create();
        context->makeCurrent(w);
        // 在expose之后调用，因为上下文绑定了窗口，加载的函数也绑定了窗口
        gladLoadGLES2Loader([](const char* name){
            auto byteArray = QByteArray::fromRawData(name, static_cast<int>(strlen(name)));
            auto ctx = QOpenGLContext::currentContext();
            return reinterpret_cast<void*>(ctx->getProcAddress(byteArray));
        });
        return context;
    }

    inline GLuint create_texture(GLsizei width, GLsizei height) {
        GLuint ret;
        glGenTextures(1, &ret);
        auto t = GL_TEXTURE_2D;
        glBindTexture(t, ret);
        glTexImage2D(t, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
        glTexParameteri(t, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(t, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // 将一个纹理附加到当前绑定的帧缓冲对象
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, t, ret, 0);
        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
            std::cout << "SubThreadFrameBuffer::render Framebuffer not complete!";
        }
        return ret;
    }

    class R {
    public:
        virtual ~R() = default;
        virtual void render() = 0;
        std::atomic<bool> show;
    };

    class Global {
        Global() {
            std::thread t([this]() {
                for (auto& r: r_list()) {
                    if (r->show) {
                        r->render();
                    }
                }
            });
        }
        static Global* instance();
        std::vector<R*> r_list() {
            std::lock_guard g(r_mutex);
            std::vector<R*> ret;
            ret.reserve(rs.size());
            for (auto& r : rs) {
                ret.push_back(r.second);
            }
            return ret;
        }
        void add(const std::string& key, R* r) {
            std::lock_guard g(r_mutex);
            if (rs.find(key) == rs.end())
            {
                rs[key] = r;
            } else
            {
                std::cout << "R" << key << " already exists!" << std::endl;
            }
        }
    protected:
        std::mutex r_mutex;
        std::map<std::string, R*> rs;
    };
}








#endif