MandelWidget.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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. //glShadeModel(GL_SMOOTH);
  215. /*CpuGenerator<double> cpg;
  216. MandelInfo mi;
  217. mi.bWidth = this->width();//ql.geometry().width();
  218. mi.bHeight = this->height(); //ql.geometry().height();
  219. mi.maxIter = 250;
  220. mi.view = viewport;
  221. auto bitmap = cpg.generate(mi);*/
  222. Bitmap<RGBColor> bitmap(1, 1);
  223. bitmap.get(0, 0) = RGBColor{50, 50, 50};
  224. tex = std::make_unique<Texture>(bitmap, context()->contextHandle());
  225. mv.start();
  226. requestRecalc();
  227. }
  228. void MandelWidget::paintGL(void)
  229. {
  230. /*if (!initialized) {
  231. emit needsUpdate(viewport);
  232. initialized = true;
  233. }*/
  234. int width = this->width();
  235. int height = this->height();
  236. /*CpuGenerator<double> cpg;
  237. ClGenerator clg;
  238. MandelGenerator& mg = cpg;
  239. MandelInfo mi;
  240. mi.bWidth = width;
  241. mi.bHeight = height;
  242. mi.maxIter = 5000;
  243. mi.view = viewport;*/
  244. //auto bitmap = mg.generate(mi);
  245. /*Bitmap<RGBColor> bitmap(1000, 1000);
  246. for (int i = 0; i < 1000 * 1000; i++)
  247. bitmap.pixels[i] = RGBColor{5, uint8_t((i % 1000) ^ (i / 1000)), 50};
  248. tex = std::make_unique<Texture>(bitmap);*/
  249. glViewport(0, 0, width, height);
  250. glMatrixMode(GL_PROJECTION);
  251. glLoadIdentity();
  252. #ifdef QT_OPENGL_ES_1
  253. glOrthof(0, width, height, 0, -1.0, 1.0);
  254. #else
  255. glOrtho(0, width, height, 0, -1.0, 1.0);
  256. #endif
  257. glMatrixMode(GL_MODELVIEW);
  258. glClear(GL_COLOR_BUFFER_BIT);
  259. glLoadIdentity();
  260. tex->drawRect(0, 0, width, height);
  261. if (rubberbandDragging)
  262. drawRubberband();
  263. printf("painted GL\n");
  264. }
  265. void MandelWidget::drawRubberband(void)
  266. {
  267. glColor3ub(10, 200, 10);
  268. glBegin(GL_LINE_LOOP);
  269. glVertex2d(rubberband.x(), rubberband.y());
  270. glVertex2d(rubberband.right(), rubberband.y());
  271. glVertex2d(rubberband.right(), rubberband.bottom());
  272. glVertex2d(rubberband.x(), rubberband.bottom());
  273. glEnd();
  274. }
  275. void MandelWidget::zoom(float scale)
  276. {
  277. viewport.zoomCenter(scale);
  278. requestRecalc();
  279. }
  280. void MandelWidget::setMaxIterations(int maxIter)
  281. {
  282. this->maxIterations = maxIter;
  283. requestRecalc();
  284. }
  285. void MandelWidget::requestRecalc()
  286. {
  287. emit needsUpdate(MandelInfo{ viewport, this->width(), this->height(), maxIterations });
  288. }
  289. void MandelWidget::resizeGL(int width, int height)
  290. {
  291. glViewport(0, 0, (GLint) width, (GLint) height);
  292. }
  293. /*void MandelWidget::redraw(void)
  294. {
  295. /*CpuGenerator<double> cpg;
  296. MandelInfo mi;
  297. mi.bWidth = this->geometry().width();//ql.geometry().width();
  298. mi.bHeight = this->geometry().height(); //ql.geometry().height();
  299. mi.maxIter = 250;
  300. mi.view = viewport;*/
  301. //update();
  302. //emit needsUpdate(viewport);
  303. //auto bitmap = cpg.generate(mi).map<uint32_t>([](RGBColor rgb) { return 255 << 24 | rgb.b << 16 | rgb.g << 8 | rgb.r; });
  304. //}
  305. void MandelWidget::resizeEvent(QResizeEvent* re)
  306. {
  307. double aspect = double(geometry().width()) / geometry().height();
  308. //if (viewport.width > viewport.height * aspect)
  309. viewport.height = (viewport.width / aspect);
  310. //else
  311. // viewport.width = (viewport.height * aspect);
  312. requestRecalc();
  313. //redraw();
  314. }
  315. void MandelWidget::mousePressEvent(QMouseEvent* me)
  316. {
  317. rubberband.setCoords(me->x(), me->y(), 0, 0);
  318. rubberbandDragging = true;
  319. }
  320. void MandelWidget::mouseMoveEvent(QMouseEvent* me)
  321. {
  322. QRectF& rect = rubberband;
  323. float aspect = float(geometry().width()) / geometry().height();
  324. rect.setBottomRight(QPoint(me->x(), me->y()));
  325. if (rect.width() > rect.height() * aspect)
  326. rect.setHeight(rect.width() / aspect);
  327. else
  328. rect.setWidth(rect.height() * aspect);
  329. if (rubberbandDragging)
  330. emit repaint();
  331. }
  332. void MandelWidget::mouseReleaseEvent(QMouseEvent* me)
  333. {
  334. QRect rect = rubberband.toRect();
  335. QRect full = this->geometry();
  336. viewport.x += double(rect.left()) * viewport.width / full.width();
  337. viewport.y += double(rect.top()) * viewport.height / full.height();
  338. viewport.width *= double(rect.width()) / full.width();
  339. viewport.height *= double(rect.height()) / full.height();
  340. viewport.normalize();
  341. rubberbandDragging = false;
  342. requestRecalc();
  343. }
  344. void MandelWidget::viewUpdated(Bitmap<RGBColor>* bitmap)
  345. {
  346. if (bitmap != nullptr) {
  347. tex = std::make_unique<Texture>(*bitmap);
  348. delete bitmap;
  349. printf("viewUpdated\n");
  350. emit repaint();
  351. }
  352. }