#include "MandelWidget.h" #include using namespace mnd; #include Texture::Texture(const Bitmap& bitmap) : context{ nullptr } { glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); long lineLength = (bitmap.width * 3 + 3) & ~3; unsigned char* pixels = new unsigned char[lineLength * bitmap.height]; for (int i = 0; i < bitmap.width; i++) { for (int j = 0; j < bitmap.height; j++) { int index = i * 3 + j * lineLength; RGBColor c = bitmap.get(i, j); pixels[index] = c.r; pixels[index + 1] = c.g; pixels[index + 2] = c.b; } } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, int(bitmap.width), int(bitmap.height), 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } Texture::Texture(const Bitmap& bitmap, QOpenGLContext* context) : context{ context } { context->functions()->glGenTextures(1, &id); context->functions()->glBindTexture(GL_TEXTURE_2D, id); long lineLength = (bitmap.width * 3 + 3) & ~3; unsigned char* pixels = new unsigned char[lineLength * bitmap.height]; for (int i = 0; i < bitmap.width; i++) { for (int j = 0; j < bitmap.height; j++) { int index = i * 3 + j * lineLength; RGBColor c = bitmap.get(i, j); pixels[index] = c.r; pixels[index + 1] = c.g; pixels[index + 2] = c.b; } } context->functions()->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, int(bitmap.width), int(bitmap.height), 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } Texture::~Texture(void) { glDeleteTextures(1, &id); } void Texture::bind(void) const { glBindTexture(GL_TEXTURE_2D, id); } void Texture::drawRect(float x, float y, float width, float height) { glColor3ub(255, 255, 255); glEnable(GL_TEXTURE_2D); bind(); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(0, 0); glVertex2f(x, y); glTexCoord2f(1, 0); glVertex2f(x + width, y); glTexCoord2f(0, 1); glVertex2f(x, y + height); glTexCoord2f(1, 1); glVertex2f(x + width, y + height); glEnd(); glDisable(GL_TEXTURE_2D); } MandelView::MandelView(mnd::Generator& generator, MandelWidget* mWidget) : generator{ &generator }, mWidget{ mWidget } //context{ new QOpenGLContext(this) } { //context->setShareContext(mWidget->context()->contextHandle()); hasToCalc.store(false); finish.store(false); } MandelView::~MandelView(void) { finish.store(true); condVar.notify_one(); //calcThread.wait(100); calcThread.wait(100); calcThread.terminate(); } void MandelView::setGenerator(mnd::Generator& value) { generator = &value; } void MandelView::start(void) { this->moveToThread(&calcThread); connect(&calcThread, SIGNAL(started()), this, SLOT(loop())); calcThread.start(); } void MandelView::loop(void) { printf("thread!\n"); fflush(stdout); //QGLWidget* hiddenWidget = new QGLWidget(nullptr, mWidget); //hiddenWidget->setVisible(false); //hiddenWidget->context()->contextHandle()->moveToThread(&calcThread); //QOpenGLContext* context = hiddenWidget->context()->contextHandle(); //context->setShareContext(mWidget->context()->contextHandle()); //context->create(); //printf("sharing: %d\n", QOpenGLContext::areSharing(hiddenWidget->context()->contextHandle(), mWidget->context()->contextHandle())); //fflush(stdout); //std::this_thread::sleep_for(std::chrono::milliseconds(3000)); std::unique_lock lock(mut); while(true) { printf("calcing!\n"); fflush(stdout); if (finish.load()) { break; } if (hasToCalc.exchange(false)) { const MandelInfo& mi = toCalc.load(); auto fmap = Bitmap(mi.bWidth, mi.bHeight); generator->generate(mi, fmap.pixels.get()); auto* bitmap = new Bitmap(fmap.map([&mi](float i) { return i > mi.maxIter ? 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) }; }); //hiddenWidget->makeCurrent(); //Texture* tex = new Texture(bitmap); //hiddenWidget->doneCurrent(); //Texture* tex = 0; emit updated(bitmap); } printf("finished calcing!\n"); fflush(stdout); condVar.wait(lock); printf("waking!\n"); fflush(stdout); } } void MandelView::adaptViewport(const MandelInfo mi) { //bmp->get(0, 0) = RGBColor{ 10, uint8_t(sin(1 / vp.width) * 127 + 127), 10 }; /*printf("adapted\n"); if (calc.valid()) { auto status = calc.wait_for(std::chrono::milliseconds(0)); if (status == std::future_status::deferred) { printf("deferred\n"); } else if (status == std::future_status::timeout) { printf("timeout\n"); } else if (status == std::future_status::ready) { printf("ready!\n"); } }*/ /*if (!calc.valid() || calc.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) { toCalc = mi; hasToCalc = true; calc = std::async([this, mi] () { QGLWidget* hiddenWidget = new QGLWidget(nullptr, (QGLWidget*) mWidget); QOpenGLContext* context = hiddenWidget->context()->contextHandle(); hiddenWidget->makeCurrent(); //context->setShareContext(mWidget->context()->contextHandle()); //context->create(); printf("sharing: %d\n", QOpenGLContext::areSharing(context, mWidget->context()->contextHandle())); fflush(stdout); //std::this_thread::sleep_for(std::chrono::milliseconds(1000)); do { auto fmap = Bitmap(mi.bWidth, mi.bHeight); generator->generate(mi, fmap.pixels.get()); auto bitmap = fmap.map([&mi](float i) { return i > mi.maxIter ? 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) }; }); Texture* tex = new Texture(bitmap, context); //Texture* tex = 0; emit updated(tex); } while(hasToCalc.exchange(false)); }); } else {*/ //std::unique_lock lock(mut, std::try_to_lock); toCalc = mi; hasToCalc.exchange(true); condVar.notify_one(); //} } MandelWidget::MandelWidget(mnd::MandelContext& ctxt, QWidget* parent) : QGLWidget{ QGLFormat(QGL::SampleBuffers), parent }, mndContext{ ctxt }, mv{ ctxt.getCpuGeneratorFloat(), this } { this->setContentsMargins(0, 0, 0, 0); this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QObject::connect(&mv, &MandelView::updated, this, &MandelWidget::viewUpdated, Qt::AutoConnection); QObject::connect(this, &MandelWidget::needsUpdate, &mv, &MandelView::adaptViewport, Qt::DirectConnection); /*if (!ctxt.getDevices().empty()) { if (auto* gen = ctxt.getDevices()[0].getGeneratorDouble(); gen) { mv.setGenerator(*gen); } }*/ } MandelWidget::~MandelWidget() { } void MandelWidget::initializeGL(void) { qglClearColor(Qt::black); glDisable(GL_DEPTH_TEST); //glShadeModel(GL_SMOOTH); /*CpuGenerator cpg; MandelInfo mi; mi.bWidth = this->width();//ql.geometry().width(); mi.bHeight = this->height(); //ql.geometry().height(); mi.maxIter = 250; mi.view = viewport; auto bitmap = cpg.generate(mi);*/ Bitmap bitmap(1, 1); bitmap.get(0, 0) = RGBColor{50, 50, 50}; tex = std::make_unique(bitmap, context()->contextHandle()); mv.start(); requestRecalc(); } void MandelWidget::paintGL(void) { /*if (!initialized) { emit needsUpdate(viewport); initialized = true; }*/ int width = this->width(); int height = this->height(); /*CpuGenerator cpg; ClGenerator clg; MandelGenerator& mg = cpg; MandelInfo mi; mi.bWidth = width; mi.bHeight = height; mi.maxIter = 5000; mi.view = viewport;*/ //auto bitmap = mg.generate(mi); /*Bitmap bitmap(1000, 1000); for (int i = 0; i < 1000 * 1000; i++) bitmap.pixels[i] = RGBColor{5, uint8_t((i % 1000) ^ (i / 1000)), 50}; tex = std::make_unique(bitmap);*/ glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); #ifdef QT_OPENGL_ES_1 glOrthof(0, width, height, 0, -1.0, 1.0); #else glOrtho(0, width, height, 0, -1.0, 1.0); #endif glMatrixMode(GL_MODELVIEW); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); tex->drawRect(0, 0, width, height); if (rubberbandDragging) drawRubberband(); printf("painted GL\n"); } void MandelWidget::drawRubberband(void) { glColor3ub(10, 200, 10); glBegin(GL_LINE_LOOP); glVertex2d(rubberband.x(), rubberband.y()); glVertex2d(rubberband.right(), rubberband.y()); glVertex2d(rubberband.right(), rubberband.bottom()); glVertex2d(rubberband.x(), rubberband.bottom()); glEnd(); } void MandelWidget::zoom(float scale) { viewport.zoomCenter(scale); requestRecalc(); } void MandelWidget::setMaxIterations(int maxIter) { this->maxIterations = maxIter; requestRecalc(); } void MandelWidget::requestRecalc() { emit needsUpdate(MandelInfo{ viewport, this->width(), this->height(), maxIterations }); } void MandelWidget::resizeGL(int width, int height) { glViewport(0, 0, (GLint) width, (GLint) height); } /*void MandelWidget::redraw(void) { /*CpuGenerator cpg; MandelInfo mi; mi.bWidth = this->geometry().width();//ql.geometry().width(); mi.bHeight = this->geometry().height(); //ql.geometry().height(); mi.maxIter = 250; mi.view = viewport;*/ //update(); //emit needsUpdate(viewport); //auto bitmap = cpg.generate(mi).map([](RGBColor rgb) { return 255 << 24 | rgb.b << 16 | rgb.g << 8 | rgb.r; }); //} void MandelWidget::resizeEvent(QResizeEvent* re) { double aspect = double(geometry().width()) / geometry().height(); //if (viewport.width > viewport.height * aspect) viewport.height = (viewport.width / aspect); //else // viewport.width = (viewport.height * aspect); requestRecalc(); //redraw(); } void MandelWidget::mousePressEvent(QMouseEvent* me) { rubberband.setCoords(me->x(), me->y(), 0, 0); rubberbandDragging = true; } void MandelWidget::mouseMoveEvent(QMouseEvent* me) { QRectF& rect = rubberband; float aspect = float(geometry().width()) / geometry().height(); rect.setBottomRight(QPoint(me->x(), me->y())); if (rect.width() > rect.height() * aspect) rect.setHeight(rect.width() / aspect); else rect.setWidth(rect.height() * aspect); if (rubberbandDragging) emit repaint(); } void MandelWidget::mouseReleaseEvent(QMouseEvent* me) { QRect rect = rubberband.toRect(); QRect full = this->geometry(); viewport.x += double(rect.left()) * viewport.width / full.width(); viewport.y += double(rect.top()) * viewport.height / full.height(); viewport.width *= double(rect.width()) / full.width(); viewport.height *= double(rect.height()) / full.height(); viewport.normalize(); rubberbandDragging = false; requestRecalc(); } void MandelWidget::viewUpdated(Bitmap* bitmap) { if (bitmap != nullptr) { tex = std::make_unique(*bitmap); delete bitmap; printf("viewUpdated\n"); emit repaint(); } }