MandelWidget.cpp 12 KB

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