EscapeTimeVisualWidget.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include "EscapeTimeVisualWidget.h"
  2. #include "Bitmap.h"
  3. #include <QOpenGLShaderProgram>
  4. #include <QOpenGLContext>
  5. #include <QOpenGLFunctions>
  6. #include <QOpenGLExtraFunctions>
  7. #include <QOpenGLFunctions_3_0>
  8. #include <vector>
  9. ETVImage::ETVImage(EscapeTimeVisualWidget& owner,
  10. const Bitmap<float>& img) :
  11. owner{ owner }
  12. {
  13. auto& gl = *owner.context()->functions();
  14. gl.glGenTextures(1, &textureId);
  15. gl.glActiveTexture(GL_TEXTURE0);
  16. gl.glBindTexture(GL_TEXTURE_2D, textureId);
  17. gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, int(img.width), int(img.height), 0, GL_RED, GL_FLOAT, img.pixels.get());
  18. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  19. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  20. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  21. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  22. gl.glBindTexture(GL_TEXTURE_2D, 0);
  23. }
  24. ETVImage::~ETVImage(void)
  25. {
  26. auto& gl = *owner.context()->functions();
  27. gl.glDeleteTextures(1, &textureId);
  28. }
  29. void ETVImage::draw(float x, float y, float w, float h,
  30. float tx, float ty, float tw, float th)
  31. {
  32. auto& gl = *owner.context()->functions();
  33. auto& gle = *owner.context()->extraFunctions();
  34. GLfloat const fbVertices[] = {
  35. 0, 0, 0.0f,
  36. 0, 256, 0.0f,
  37. 256, 0, 0.0f,
  38. 256, 256, 0.0f,
  39. };
  40. GLfloat const vertices[] = {
  41. x, y, 0.0f,
  42. x, y + h, 0.0f,
  43. x + w, y, 0.0f,
  44. x + w, y + h, 0.0f,
  45. };
  46. GLfloat const texCoords[] = {
  47. tx, ty,
  48. tx, ty + th,
  49. tx + tw, ty,
  50. tx + tw, ty + th,
  51. };
  52. GLfloat const fullTexCoords[] = {
  53. 0, 0,
  54. 0, 1,
  55. 1, 0,
  56. 1, 1,
  57. };
  58. QColor color{ 255, 255, 255 };
  59. auto& program = owner.program;
  60. int vertexLoc = program->attributeLocation("vertex");
  61. int texCoordsLoc = program->attributeLocation("texCoord");
  62. int colorLocation = program->uniformLocation("color");
  63. int texLoc = program->uniformLocation("tex");
  64. int gradLoc = program->uniformLocation("gradient");
  65. program->setAttributeArray(vertexLoc, fbVertices, 3);
  66. program->setAttributeArray(texCoordsLoc, texCoords, 2);
  67. program->enableAttributeArray(vertexLoc);
  68. program->enableAttributeArray(texCoordsLoc);
  69. program->setUniformValue(colorLocation, color);
  70. gl.glEnable(GL_TEXTURE_2D);
  71. owner.program->bind();
  72. //GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
  73. //gle.glDrawBuffers(1, drawBuffers);
  74. if(gl.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  75. printf("error intitializing framebuffer\n");
  76. }
  77. gl.glBindFramebuffer(GL_FRAMEBUFFER, owner.tileFramebuffer);
  78. gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, owner.tileTexture, 0);
  79. //gl.glViewport(0, 0, 256, 256);
  80. gl.glUniform1i(texLoc, 0);
  81. gl.glUniform1i(gradLoc, 2);
  82. gl.glActiveTexture(GL_TEXTURE0);
  83. gl.glBindTexture(GL_TEXTURE_2D, textureId);
  84. gl.glActiveTexture(GL_TEXTURE2);
  85. gl.glBindTexture(GL_TEXTURE_2D, owner.gradientTextureId);
  86. gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  87. program->disableAttributeArray(vertexLoc);
  88. program->disableAttributeArray(texCoordsLoc);
  89. owner.renderTextures->bind();
  90. gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
  91. //gl.glViewport(0, 0, owner.getResolutionX(), owner.getResolutionY());
  92. int rtVertexLoc = owner.renderTextures->attributeLocation("vertex");
  93. int rtTexCoordsLoc = owner.renderTextures->attributeLocation("texCoord");
  94. int rtTexLoc = owner.renderTextures->attributeLocation("tex");
  95. gl.glActiveTexture(GL_TEXTURE0);
  96. gl.glUniform1i(rtTexLoc, 0);
  97. owner.renderTextures->setAttributeArray(rtVertexLoc, vertices, 3);
  98. owner.renderTextures->setAttributeArray(rtTexCoordsLoc, fullTexCoords, 2);
  99. owner.renderTextures->enableAttributeArray(rtVertexLoc);
  100. owner.renderTextures->enableAttributeArray(rtTexCoordsLoc);
  101. gl.glBindTexture(GL_TEXTURE_2D, owner.tileTexture);
  102. gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  103. owner.renderTextures->disableAttributeArray(rtVertexLoc);
  104. owner.renderTextures->disableAttributeArray(rtTexCoordsLoc);
  105. gl.glActiveTexture(GL_TEXTURE0);
  106. }
  107. EscapeTimeVisualWidget::EscapeTimeVisualWidget(QWidget* parent) :
  108. QOpenGLWidget{ parent },
  109. gradientNeedsUpdate{ false }
  110. {
  111. }
  112. void EscapeTimeVisualWidget::setGradient(Gradient newGradient)
  113. {
  114. this->gradient = newGradient;
  115. gradientNeedsUpdate = true;
  116. update();
  117. }
  118. const Gradient& EscapeTimeVisualWidget::getGradient(void)
  119. {
  120. return gradient;
  121. }
  122. void EscapeTimeVisualWidget::initializeGL(void)
  123. {
  124. auto& gl = *this->context()->functions();
  125. gl.glClearColor(0, 0, 0, 0);
  126. gl.glDisable(GL_DEPTH_TEST);
  127. // looks not even better
  128. //gl.glEnable(GL_FRAMEBUFFER_SRGB);
  129. //glShadeModel(GL_SMOOTH);
  130. renderTextures = new QOpenGLShaderProgram{ this->context() };
  131. renderTextures->addShaderFromSourceCode(QOpenGLShader::Vertex,
  132. "attribute highp vec4 vertex;\n"
  133. "attribute highp vec2 texCoord;\n"
  134. "uniform highp mat4 matrix;\n"
  135. "varying highp vec2 texc;\n"
  136. "void main(void)\n"
  137. "{\n"
  138. " gl_Position = matrix * vertex;\n"
  139. " texc = texCoord;\n"
  140. "}");
  141. renderTextures->addShaderFromSourceCode(QOpenGLShader::Fragment,
  142. "#version 110\n"
  143. "uniform sampler2D tex;\n"
  144. "varying highp vec2 texc;\n"
  145. "void main(void)\n"
  146. "{\n"
  147. " gl_FragColor = texture2D(tex, texc);\n"
  148. "}");
  149. renderTextures->link();
  150. program = new QOpenGLShaderProgram{ this->context() };
  151. bool vert = program->addShaderFromSourceCode(QOpenGLShader::Vertex,
  152. "attribute highp vec4 vertex;\n"
  153. "attribute highp vec2 texCoord;\n"
  154. "uniform highp mat4 matrix;\n"
  155. "varying highp vec2 texc;\n"
  156. "void main(void)\n"
  157. "{\n"
  158. " gl_Position = matrix * vertex;\n"
  159. " texc = texCoord;\n"
  160. "}");
  161. // TODO rewrite this monster
  162. bool frag = program->addShaderFromSourceCode(QOpenGLShader::Fragment,
  163. "#version 110\n"
  164. "uniform sampler2D gradient;\n"
  165. "uniform sampler2D tex;\n"
  166. "uniform mediump vec4 color;\n"
  167. "uniform highp float gradientScaler;\n"
  168. "varying highp vec2 texc;\n"
  169. "void main(void)\n"
  170. "{\n"
  171. " float v = texture2D(tex, texc).r;\n"
  172. /*" vec2 size = textureSize(tex, 0);\n"
  173. " size = vec2(256.0, 256.0);\n"
  174. " vec2 accPoint = texc * size;\n"
  175. " vec2 ip = floor(accPoint);\n"
  176. " vec2 fp = fract(accPoint);\n"
  177. " vec4 inter = textureGather(tex, ip / size, 0);\n"
  178. " vec4 col1 = texture2D(gradient, vec2(inter.x*0.005, 0.0));\n"
  179. " vec4 col2 = texture2D(gradient, vec2(inter.y*0.005, 0.0));\n"
  180. " vec4 col3 = texture2D(gradient, vec2(inter.z*0.005, 0.0));\n"
  181. " vec4 col4 = texture2D(gradient, vec2(inter.w*0.005, 0.0));\n"
  182. " vec4 col = mix(mix(col4, col3, fp.x), mix(col1, col2, fp.x), fp.y);\n"*/
  183. " gl_FragColor = texture2D(gradient, vec2(v*0.005, 0.0));\n"
  184. //" gl_FragColor = col;\n"
  185. // " gl_FragColor = gl_FragColor * texture2D(tex, texc);\n"
  186. // " float v = texture2D(tex, texc).r;\n"
  187. // " gl_FragColor = vec4(v, 1.0 - v, v*v, 1);\n"
  188. // " gl_FragColor.g = 0.3;\n"
  189. "}");
  190. //program.link();
  191. bool bound = program->bind();
  192. bound = renderTextures->bind();
  193. int vertexLoc = program->attributeLocation("vertex");
  194. int texCoordsLoc = program->attributeLocation("texCoord");
  195. int colorLocation = program->uniformLocation("color");
  196. int texLoc = program->uniformLocation("tex");
  197. int gradLoc = program->uniformLocation("gradient");
  198. int gradientScaler = program->uniformLocation("gradientScaler");
  199. auto& gle = *this->context()->extraFunctions();
  200. gl.glGenTextures(1, &tileTexture);
  201. gl.glBindTexture(GL_TEXTURE_2D, tileTexture);
  202. gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
  203. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  204. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  205. gl.glGenFramebuffers(1, &tileFramebuffer);
  206. gl.glBindFramebuffer(GL_FRAMEBUFFER, tileFramebuffer);
  207. gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tileTexture, 0);
  208. GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
  209. gle.glDrawBuffers(1, drawBuffers);
  210. if(gl.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  211. printf("error intitializing framebuffer\n");
  212. }
  213. unsigned char pix[] = { 255, 0, 0, 0, 255, 0, 0, 0, 255 };
  214. GLuint id;
  215. gl.glEnable(GL_TEXTURE_2D);
  216. gl.glGenTextures(1, &id);
  217. gl.glBindTexture(GL_TEXTURE_2D, id);
  218. gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 3, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<char*> (pix));
  219. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  220. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  221. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  222. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  223. gl.glBindTexture(GL_TEXTURE_2D, 0);
  224. gradientTextureId = id;
  225. gl.glDisable(GL_DEPTH_TEST);
  226. //gl3.glBindSampler(0, id);
  227. }
  228. void EscapeTimeVisualWidget::resizeGL(int w, int h)
  229. {
  230. auto& gl = *this->context()->functions();
  231. float pixelRatio = this->devicePixelRatioF();
  232. //pixelRatio = 1.0 / 32;
  233. float newW = w * pixelRatio;
  234. float newH = h * pixelRatio;
  235. setResolutionX(newW);
  236. setResolutionY(newH);
  237. gl.glViewport(0, 0, newW, newH);
  238. QMatrix4x4 pmvMatrix;
  239. pmvMatrix.ortho(QRectF{ 0, 0, newW, newH });
  240. int matrixLocation = program->uniformLocation("matrix");
  241. int rtMatrixLocation = renderTextures->uniformLocation("matrix");
  242. program->setUniformValue(matrixLocation, pmvMatrix);
  243. renderTextures->setUniformValue(rtMatrixLocation, pmvMatrix);
  244. }
  245. void EscapeTimeVisualWidget::paintGL(void)
  246. {
  247. if (gradientNeedsUpdate)
  248. updateGradient();
  249. /*ETVImage etvi{ *this };
  250. auto& gl = *this->context()->functions();
  251. gl.glClearColor(0.0, 0.2, 0.0, 1.0);
  252. gl.glClear(GL_COLOR_BUFFER_BIT);
  253. etvi.draw(100, 100, 700, 700);*/
  254. }
  255. void EscapeTimeVisualWidget::updateGradient(void)
  256. {
  257. auto& gl = *this->context()->functions();
  258. const int len = 512;
  259. std::unique_ptr<uint8_t[]> pixels = std::make_unique<uint8_t[]>(len * 3);
  260. for (int i = 0; i < len; i++) {
  261. RGBColor c = gradient.get(gradient.getMax() * i / len);
  262. pixels[i * 3] = c.r;
  263. pixels[i * 3 + 1] = c.g;
  264. pixels[i * 3 + 2] = c.b;
  265. }
  266. gl.glEnable(GL_TEXTURE_2D);
  267. gl.glBindTexture(GL_TEXTURE_2D, gradientTextureId);
  268. gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, len, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<unsigned char*> (pixels.get()));
  269. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  270. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  271. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  272. gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  273. gl.glBindTexture(GL_TEXTURE_2D, 0);
  274. gradientNeedsUpdate = false;
  275. }
  276. void EscapeTimeVisualWidget::setResolutionX(int w)
  277. {
  278. resolutionX = w;
  279. }
  280. void EscapeTimeVisualWidget::setResolutionY(int h)
  281. {
  282. resolutionY = h;
  283. }
  284. int EscapeTimeVisualWidget::getResolutionX(void) const
  285. {
  286. return resolutionX;
  287. }
  288. int EscapeTimeVisualWidget::getResolutionY(void) const
  289. {
  290. return resolutionY;
  291. }