MandelWidget.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. #include "MandelWidget.h"
  2. #include <cmath>
  3. using namespace mnd;
  4. #include <QOpenGLVertexArrayObject>
  5. Texture::Texture(const Bitmap<RGBColor>& bitmap) :
  6. context{ nullptr }
  7. {
  8. glGenTextures(1, &id);
  9. glBindTexture(GL_TEXTURE_2D, id);
  10. long lineLength = (bitmap.width * 3 + 3) & ~3;
  11. unsigned char* pixels = new unsigned char[lineLength * bitmap.height];
  12. for (int i = 0; i < bitmap.width; i++) {
  13. for (int j = 0; j < bitmap.height; j++) {
  14. int index = i * 3 + j * lineLength;
  15. RGBColor c = bitmap.get(i, j);
  16. pixels[index] = c.r;
  17. pixels[index + 1] = c.g;
  18. pixels[index + 2] = c.b;
  19. }
  20. }
  21. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, int(bitmap.width), int(bitmap.height), 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
  22. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  23. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  24. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  25. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  26. }
  27. Texture::Texture(const Bitmap<RGBColor>& bitmap, QOpenGLContext* context) :
  28. context{ context }
  29. {
  30. context->functions()->glGenTextures(1, &id);
  31. context->functions()->glBindTexture(GL_TEXTURE_2D, id);
  32. long lineLength = (bitmap.width * 3 + 3) & ~3;
  33. unsigned char* pixels = new unsigned char[lineLength * bitmap.height];
  34. for (int i = 0; i < bitmap.width; i++) {
  35. for (int j = 0; j < bitmap.height; j++) {
  36. int index = i * 3 + j * lineLength;
  37. RGBColor c = bitmap.get(i, j);
  38. pixels[index] = c.r;
  39. pixels[index + 1] = c.g;
  40. pixels[index + 2] = c.b;
  41. }
  42. }
  43. context->functions()->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, int(bitmap.width), int(bitmap.height), 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
  44. context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  45. context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  46. context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  47. context->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  48. }
  49. Texture::~Texture(void)
  50. {
  51. glDeleteTextures(1, &id);
  52. }
  53. void Texture::bind(void) const
  54. {
  55. glBindTexture(GL_TEXTURE_2D, id);
  56. }
  57. void Texture::drawRect(float x, float y, float width, float height)
  58. {
  59. glColor3ub(255, 255, 255);
  60. glEnable(GL_TEXTURE_2D);
  61. bind();
  62. glBegin(GL_TRIANGLE_STRIP);
  63. glTexCoord2f(0, 0);
  64. glVertex2f(x, y);
  65. glTexCoord2f(1, 0);
  66. glVertex2f(x + width, y);
  67. glTexCoord2f(0, 1);
  68. glVertex2f(x, y + height);
  69. glTexCoord2f(1, 1);
  70. glVertex2f(x + width, y + height);
  71. glEnd();
  72. glDisable(GL_TEXTURE_2D);
  73. }
  74. MandelView::MandelView(mnd::Generator& generator, Gradient &gradient, MandelWidget* mWidget) :
  75. generator{ &generator },
  76. gradient{ gradient },
  77. mWidget{ mWidget }
  78. //context{ new QOpenGLContext(this) }
  79. {
  80. //context->setShareContext(mWidget->context()->contextHandle());
  81. hasToCalc.store(false);
  82. finish.store(false);
  83. }
  84. MandelView::~MandelView(void)
  85. {
  86. finish.store(true);
  87. condVar.notify_one();
  88. //calcThread.wait(100);
  89. calcThread.wait(100);
  90. calcThread.terminate();
  91. }
  92. void MandelView::setGenerator(mnd::Generator& value)
  93. {
  94. generator = &value;
  95. }
  96. void MandelView::start(void)
  97. {
  98. this->moveToThread(&calcThread);
  99. connect(&calcThread, SIGNAL(started()), this, SLOT(loop()));
  100. calcThread.start();
  101. }
  102. void MandelView::loop(void)
  103. {
  104. printf("thread!\n"); fflush(stdout);
  105. //QGLWidget* hiddenWidget = new QGLWidget(nullptr, mWidget);
  106. //hiddenWidget->setVisible(false);
  107. //hiddenWidget->context()->contextHandle()->moveToThread(&calcThread);
  108. //QOpenGLContext* context = hiddenWidget->context()->contextHandle();
  109. //context->setShareContext(mWidget->context()->contextHandle());
  110. //context->create();
  111. //printf("sharing: %d\n", QOpenGLContext::areSharing(hiddenWidget->context()->contextHandle(), mWidget->context()->contextHandle()));
  112. //fflush(stdout);
  113. //std::this_thread::sleep_for(std::chrono::milliseconds(3000));
  114. std::unique_lock<std::mutex> lock(mut);
  115. while(true) {
  116. printf("calcing!\n"); fflush(stdout);
  117. if (finish.load()) {
  118. break;
  119. }
  120. if (hasToCalc.exchange(false)) {
  121. const MandelInfo& mi = toCalc.load();
  122. auto fmap = Bitmap<float>(mi.bWidth, mi.bHeight);
  123. generator->generate(mi, fmap.pixels.get());
  124. auto* bitmap = new Bitmap<RGBColor>(fmap.map<RGBColor>([&mi, this](float i) {
  125. return i >= mi.maxIter ? RGBColor{ 0, 0, 0 } : gradient.get(i);
  126. }));
  127. /*return i >= mi.maxIter ?
  128. RGBColor{ 0,0,0 } :
  129. RGBColor{ uint8_t(cos(i * 0.015f) * 127 + 127),
  130. uint8_t(sin(i * 0.01f) * 127 + 127),
  131. uint8_t(i) }; }));//uint8_t(::sin(i * 0.01f) * 100 + 100), uint8_t(i) }; });
  132. */
  133. //hiddenWidget->makeCurrent();
  134. //Texture* tex = new Texture(bitmap);
  135. //hiddenWidget->doneCurrent();
  136. //Texture* tex = 0;
  137. emit updated(bitmap);
  138. }
  139. printf("finished calcing!\n"); fflush(stdout);
  140. condVar.wait(lock);
  141. printf("waking!\n"); fflush(stdout);
  142. }
  143. }
  144. void MandelView::adaptViewport(const MandelInfo mi)
  145. {
  146. //bmp->get(0, 0) = RGBColor{ 10, uint8_t(sin(1 / vp.width) * 127 + 127), 10 };
  147. /*printf("adapted\n");
  148. if (calc.valid()) {
  149. auto status = calc.wait_for(std::chrono::milliseconds(0));
  150. if (status == std::future_status::deferred) {
  151. printf("deferred\n");
  152. } else if (status == std::future_status::timeout) {
  153. printf("timeout\n");
  154. } else if (status == std::future_status::ready) {
  155. printf("ready!\n");
  156. }
  157. }*/
  158. /*if (!calc.valid() || calc.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) {
  159. toCalc = mi;
  160. hasToCalc = true;
  161. calc = std::async([this, mi] () {
  162. QGLWidget* hiddenWidget = new QGLWidget(nullptr, (QGLWidget*) mWidget);
  163. QOpenGLContext* context = hiddenWidget->context()->contextHandle();
  164. hiddenWidget->makeCurrent();
  165. //context->setShareContext(mWidget->context()->contextHandle());
  166. //context->create();
  167. printf("sharing: %d\n", QOpenGLContext::areSharing(context, mWidget->context()->contextHandle()));
  168. fflush(stdout);
  169. //std::this_thread::sleep_for(std::chrono::milliseconds(1000));
  170. do {
  171. auto fmap = Bitmap<float>(mi.bWidth, mi.bHeight);
  172. generator->generate(mi, fmap.pixels.get());
  173. auto bitmap = fmap.map<RGBColor>([&mi](float i) { return i > mi.maxIter ?
  174. RGBColor{ 0,0,0 } :
  175. RGBColor{ uint8_t(cos(i * 0.015f) * 127 + 127),
  176. uint8_t(sin(i * 0.01f) * 127 + 127),
  177. uint8_t(i) }; });//uint8_t(::sin(i * 0.01f) * 100 + 100), uint8_t(i) }; });
  178. Texture* tex = new Texture(bitmap, context);
  179. //Texture* tex = 0;
  180. emit updated(tex);
  181. } while(hasToCalc.exchange(false));
  182. });
  183. }
  184. else {*/
  185. //std::unique_lock<std::mutex> lock(mut, std::try_to_lock);
  186. toCalc = mi;
  187. hasToCalc.exchange(true);
  188. condVar.notify_one();
  189. //}
  190. }
  191. MandelWidget::MandelWidget(mnd::MandelContext& ctxt, QWidget* parent) :
  192. QGLWidget{ QGLFormat(QGL::SampleBuffers), parent },
  193. mndContext{ ctxt },
  194. mv{ ctxt.getCpuGeneratorFloat(), gradient, this }
  195. {
  196. this->setContentsMargins(0, 0, 0, 0);
  197. this->setSizePolicy(QSizePolicy::Expanding,
  198. QSizePolicy::Expanding);
  199. QObject::connect(&mv, &MandelView::updated, this, &MandelWidget::viewUpdated, Qt::AutoConnection);
  200. QObject::connect(this, &MandelWidget::needsUpdate, &mv, &MandelView::adaptViewport, Qt::DirectConnection);
  201. if (!ctxt.getDevices().empty()) {
  202. if (auto* gen = ctxt.getDevices()[0].getGeneratorDouble(); gen) {
  203. mv.setGenerator(*gen);
  204. }
  205. }
  206. }
  207. MandelWidget::~MandelWidget()
  208. {
  209. }
  210. void MandelWidget::initializeGL(void)
  211. {
  212. qglClearColor(Qt::black);
  213. glDisable(GL_DEPTH_TEST);
  214. // looks not even better
  215. glDisable(GL_FRAMEBUFFER_SRGB);
  216. //glShadeModel(GL_SMOOTH);
  217. /*CpuGenerator<double> cpg;
  218. MandelInfo mi;
  219. mi.bWidth = this->width();//ql.geometry().width();
  220. mi.bHeight = this->height(); //ql.geometry().height();
  221. mi.maxIter = 250;
  222. mi.view = viewport;
  223. auto bitmap = cpg.generate(mi);*/
  224. Bitmap<RGBColor> bitmap(1, 1);
  225. bitmap.get(0, 0) = RGBColor{50, 50, 50};
  226. tex = std::make_unique<Texture>(bitmap, context()->contextHandle());
  227. mv.start();
  228. requestRecalc();
  229. }
  230. void MandelWidget::paintGL(void)
  231. {
  232. /*if (!initialized) {
  233. emit needsUpdate(viewport);
  234. initialized = true;
  235. }*/
  236. int width = this->width();
  237. int height = this->height();
  238. /*CpuGenerator<double> cpg;
  239. ClGenerator clg;
  240. MandelGenerator& mg = cpg;
  241. MandelInfo mi;
  242. mi.bWidth = width;
  243. mi.bHeight = height;
  244. mi.maxIter = 5000;
  245. mi.view = viewport;*/
  246. //auto bitmap = mg.generate(mi);
  247. /*Bitmap<RGBColor> bitmap(1000, 1000);
  248. for (int i = 0; i < 1000 * 1000; i++)
  249. bitmap.pixels[i] = RGBColor{5, uint8_t((i % 1000) ^ (i / 1000)), 50};
  250. tex = std::make_unique<Texture>(bitmap);*/
  251. glViewport(0, 0, width, height);
  252. glMatrixMode(GL_PROJECTION);
  253. glLoadIdentity();
  254. #ifdef QT_OPENGL_ES_1
  255. glOrthof(0, width, height, 0, -1.0, 1.0);
  256. #else
  257. glOrtho(0, width, height, 0, -1.0, 1.0);
  258. #endif
  259. glMatrixMode(GL_MODELVIEW);
  260. glClear(GL_COLOR_BUFFER_BIT);
  261. glLoadIdentity();
  262. tex->drawRect(0, 0, width, height);
  263. if (rubberbandDragging)
  264. drawRubberband();
  265. printf("painted GL\n");
  266. }
  267. void MandelWidget::drawRubberband(void)
  268. {
  269. glColor3ub(10, 200, 10);
  270. glBegin(GL_LINE_LOOP);
  271. glVertex2d(rubberband.x(), rubberband.y());
  272. glVertex2d(rubberband.right(), rubberband.y());
  273. glVertex2d(rubberband.right(), rubberband.bottom());
  274. glVertex2d(rubberband.x(), rubberband.bottom());
  275. glEnd();
  276. }
  277. void MandelWidget::zoom(float scale)
  278. {
  279. viewport.zoomCenter(scale);
  280. requestRecalc();
  281. }
  282. void MandelWidget::setMaxIterations(int maxIter)
  283. {
  284. this->maxIterations = maxIter;
  285. requestRecalc();
  286. }
  287. void MandelWidget::requestRecalc()
  288. {
  289. emit needsUpdate(MandelInfo{ viewport, this->width(), this->height(), maxIterations });
  290. }
  291. void MandelWidget::resizeGL(int width, int height)
  292. {
  293. glViewport(0, 0, (GLint) width, (GLint) height);
  294. }
  295. /*void MandelWidget::redraw(void)
  296. {
  297. /*CpuGenerator<double> cpg;
  298. MandelInfo mi;
  299. mi.bWidth = this->geometry().width();//ql.geometry().width();
  300. mi.bHeight = this->geometry().height(); //ql.geometry().height();
  301. mi.maxIter = 250;
  302. mi.view = viewport;*/
  303. //update();
  304. //emit needsUpdate(viewport);
  305. //auto bitmap = cpg.generate(mi).map<uint32_t>([](RGBColor rgb) { return 255 << 24 | rgb.b << 16 | rgb.g << 8 | rgb.r; });
  306. //}
  307. void MandelWidget::resizeEvent(QResizeEvent* re)
  308. {
  309. double aspect = double(geometry().width()) / geometry().height();
  310. //if (viewport.width > viewport.height * aspect)
  311. viewport.height = (viewport.width / aspect);
  312. //else
  313. // viewport.width = (viewport.height * aspect);
  314. requestRecalc();
  315. //redraw();
  316. }
  317. void MandelWidget::mousePressEvent(QMouseEvent* me)
  318. {
  319. rubberband.setCoords(me->x(), me->y(), 0, 0);
  320. rubberbandDragging = true;
  321. }
  322. void MandelWidget::mouseMoveEvent(QMouseEvent* me)
  323. {
  324. QRectF& rect = rubberband;
  325. float aspect = float(geometry().width()) / geometry().height();
  326. rect.setBottomRight(QPoint(me->x(), me->y()));
  327. if (rect.width() > rect.height() * aspect)
  328. rect.setHeight(rect.width() / aspect);
  329. else
  330. rect.setWidth(rect.height() * aspect);
  331. if (rubberbandDragging)
  332. emit repaint();
  333. }
  334. void MandelWidget::mouseReleaseEvent(QMouseEvent* me)
  335. {
  336. QRect rect = rubberband.toRect();
  337. QRect full = this->geometry();
  338. viewport.x += double(rect.left()) * viewport.width / full.width();
  339. viewport.y += double(rect.top()) * viewport.height / full.height();
  340. viewport.width *= double(rect.width()) / full.width();
  341. viewport.height *= double(rect.height()) / full.height();
  342. viewport.normalize();
  343. rubberbandDragging = false;
  344. requestRecalc();
  345. }
  346. void MandelWidget::viewUpdated(Bitmap<RGBColor>* bitmap)
  347. {
  348. if (bitmap != nullptr) {
  349. tex = std::make_unique<Texture>(*bitmap);
  350. delete bitmap;
  351. printf("viewUpdated\n");
  352. emit repaint();
  353. }
  354. }