123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- #include "EscapeTimeVisualWidget.h"
- #include "Bitmap.h"
- #include <QOpenGLShaderProgram>
- #include <QOpenGLContext>
- #include <QOpenGLFunctions>
- #include <QOpenGLExtraFunctions>
- #include <QOpenGLFunctions_3_0>
- #include <QOpenGLFunctions_4_0_Core>
- #include <vector>
- ETVImage::ETVImage(EscapeTimeVisualWidget& owner,
- const Bitmap<float>& img) :
- owner{ owner }
- {
- auto& gl = *owner.context()->functions();
- gl.glGenTextures(1, &textureId);
- gl.glActiveTexture(GL_TEXTURE0);
- gl.glBindTexture(GL_TEXTURE_2D, textureId);
- gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, int(img.width), int(img.height), 0, GL_RED, GL_FLOAT, img.pixels.get());
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl.glBindTexture(GL_TEXTURE_2D, 0);
- }
- ETVImage::~ETVImage(void)
- {
- auto& gl = *owner.context()->functions();
- gl.glDeleteTextures(1, &textureId);
- }
- void ETVImage::draw(float x, float y, float w, float h,
- float tx, float ty, float tw, float th)
- {
- auto& gl = *owner.context()->functions();
- auto& gle = *owner.context()->extraFunctions();
- GLfloat const fbVertices[] = {
- 0, 0, 0.0f,
- 0, 256, 0.0f,
- 256, 0, 0.0f,
- 256, 256, 0.0f,
- };
- GLfloat const vertices[] = {
- x, y, 0.0f,
- x, y + h, 0.0f,
- x + w, y, 0.0f,
- x + w, y + h, 0.0f,
- };
- GLfloat const texCoords[] = {
- tx, ty,
- tx, ty + th,
- tx + tw, ty,
- tx + tw, ty + th,
- };
- GLfloat const fullTexCoords[] = {
- 0, 0,
- 0, 1,
- 1, 0,
- 1, 1,
- };
- QColor color{ 255, 255, 255 };
- auto& program = owner.program;
- program->bind();
- int vertexLoc = program->attributeLocation("vertex");
- int texCoordsLoc = program->attributeLocation("texCoord");
- int colorLocation = program->uniformLocation("color");
- int texLoc = program->uniformLocation("tex");
- int gradLoc = program->uniformLocation("gradient");
- int gradientScaler = program->uniformLocation("gradientScaler");
- int maxIterations = program->uniformLocation("maxIterations");
- program->setAttributeArray(vertexLoc, vertices, 3);
- program->setAttributeArray(texCoordsLoc, texCoords, 2);
- program->enableAttributeArray(vertexLoc);
- program->enableAttributeArray(texCoordsLoc);
- program->setUniformValue(colorLocation, color);
- program->setUniformValue(gradientScaler, 1.0f / float(owner.gradientTextureMax));
- program->setUniformValue(maxIterations, float(owner.maxIterations));
- QMatrix4x4 pmvMatrix;
- pmvMatrix.ortho(QRect{ 0, 0, owner.getResolutionX(), owner.getResolutionY() });
- int matrixLocation = program->uniformLocation("matrix");
- program->setUniformValue(matrixLocation, pmvMatrix);
- gl.glEnable(GL_TEXTURE_2D);
- //GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
- //gle.glDrawBuffers(1, drawBuffers);
- gl.glBindFramebuffer(GL_FRAMEBUFFER, owner.tileFramebuffer);
- gl.glDisable(GL_DEPTH_TEST);
- if(gl.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- printf("error intitializing framebuffer\n");
- }
- gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, owner.tileTexture, 0);
- //gl.glViewport(0, 0, 256, 256);
- gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
- gl.glUniform1i(texLoc, 0);
- gl.glUniform1i(gradLoc, 2);
- gl.glActiveTexture(GL_TEXTURE0);
- gl.glBindTexture(GL_TEXTURE_2D, textureId);
- gl.glActiveTexture(GL_TEXTURE2);
- gl.glBindTexture(GL_TEXTURE_2D, owner.gradientTextureId);
- gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- program->disableAttributeArray(vertexLoc);
- program->disableAttributeArray(texCoordsLoc);
- /*owner.renderTextures->bind();
- gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
- //gl.glViewport(0, 0, owner.getResolutionX(), owner.getResolutionY());
- int rtVertexLoc = owner.renderTextures->attributeLocation("vertex");
- int rtTexCoordsLoc = owner.renderTextures->attributeLocation("texCoord");
- int rtTexLoc = owner.renderTextures->attributeLocation("tex");
- gl.glActiveTexture(GL_TEXTURE0);
- gl.glUniform1i(rtTexLoc, 0);
- owner.renderTextures->setAttributeArray(rtVertexLoc, vertices, 3);
- owner.renderTextures->setAttributeArray(rtTexCoordsLoc, fullTexCoords, 2);
- owner.renderTextures->enableAttributeArray(rtVertexLoc);
- owner.renderTextures->enableAttributeArray(rtTexCoordsLoc);
- gl.glBindTexture(GL_TEXTURE_2D, owner.tileTexture);
- //if (rand() % 2)
- //gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- owner.renderTextures->disableAttributeArray(rtVertexLoc);
- owner.renderTextures->disableAttributeArray(rtTexCoordsLoc);
- */
- gl.glActiveTexture(GL_TEXTURE0);
- }
- EscapeTimeVisualWidget::EscapeTimeVisualWidget(QWidget* parent) :
- QOpenGLWidget{ parent },
- gradientTextureId{ 0 },
- gradientTextureMax{ 1.0f },
- gradientNeedsUpdate{ false }
- {
- }
- void EscapeTimeVisualWidget::setGradient(Gradient newGradient)
- {
- this->gradient = newGradient;
- gradientNeedsUpdate = true;
- update();
- }
- const Gradient& EscapeTimeVisualWidget::getGradient(void)
- {
- return gradient;
- }
- void EscapeTimeVisualWidget::initializeGL(void)
- {
- auto& gl = *this->context()->functions();
- gl.glClearColor(0, 0, 0, 0);
- gl.glDisable(GL_DEPTH_TEST);
- fprintf(stdout, "version: %s\n", gl.glGetString(GL_VERSION));
- fflush(stdout);
- // looks not even better
- //gl.glEnable(GL_FRAMEBUFFER_SRGB);
- //glShadeModel(GL_SMOOTH);
- renderTextures = new QOpenGLShaderProgram{ this->context() };
- renderTextures->addShaderFromSourceCode(QOpenGLShader::Vertex,
- "attribute highp vec4 vertex;\n"
- "attribute highp vec2 texCoord;\n"
- "uniform highp mat4 matrix;\n"
- "varying highp vec2 texc;\n"
- "void main(void)\n"
- "{\n"
- " gl_Position = matrix * vertex;\n"
- " texc = texCoord;\n"
- "}");
- renderTextures->addShaderFromSourceCode(QOpenGLShader::Fragment,
- // "#version 110\n"
- "uniform sampler2D tex;\n"
- "varying highp vec2 texc;\n"
- "void main(void)\n"
- "{\n"
- " gl_FragColor = texture2D(tex, texc);\n"
- "}");
- renderTextures->link();
- juliaPreviewer = new QOpenGLShaderProgram{ this->context() };
- juliaPreviewer->addShaderFromSourceCode(QOpenGLShader::Vertex,
- "attribute highp vec4 vertex;\n"
- "attribute highp vec2 texCoord;\n"
- "uniform highp mat4 matrix;\n"
- "varying highp vec2 texc;\n"
- "void main(void)\n"
- "{\n"
- " gl_Position = matrix * vertex;\n"
- " texc = texCoord;\n"
- "}");
- juliaPreviewer->addShaderFromSourceCode(QOpenGLShader::Fragment,
- // "#version 110\n"
- "uniform sampler2D gradient;\n"
- "uniform highp float gradientScaler;\n"
- "const highp float maxIterations = 350.0;\n"
- "varying highp vec2 texc;\n"
- "uniform highp float juliaX;\n"
- "uniform highp float juliaY;\n"
- "const highp float left = -1.5;\n"
- "const highp float right = 1.5;\n"
- "const highp float top = -1.5;\n"
- "const highp float bottom = 1.5;\n"
- "highp float map(highp float a, highp float b, highp float v) {\n"
- " return (1.0 - v) * a + b * v;\n"
- "}\n"
- "highp float iterate(highp float x, highp float y, highp float ca, highp float cb) {\n"
- " int k = 0;\n"
- " highp float a = x;\n"
- " highp float b = y;\n"
- " while(k <= int(maxIterations)) {\n"
- " highp float aa = a * a;\n"
- " highp float bb = b * b;\n"
- " highp float abab = 2.0 * a * b;\n"
- " a = aa - bb + ca;\n"
- " b = abab + cb;\n"
- " if (aa + bb >= 16.0) break;\n"
- " k = k + 1;\n"
- " }\n"
- " return float(k) + 1 - log2(log(a * a + b * b) * 0.5);\n"
- "}\n"
- "void main(void)\n"
- "{\n"
- " highp float x = map(left, right, texc.x);\n"
- " highp float y = map(top, bottom, texc.y);\n"
- " highp float v = iterate(x, y, juliaX, juliaY);\n"
- " if (v >= maxIterations) {\n"
- " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
- " } else {\n"
- " highp float vnorm = v * gradientScaler;\n"
- " gl_FragColor = texture2D(gradient, vec2(vnorm, 0.0));\n"
- " }\n"
- //" gl_FragColor = vec4(vnorm, 0.0, 0.0, 0.0);\n"
- "}");
- juliaPreviewer->link();
- program = new QOpenGLShaderProgram{ this->context() };
- bool vert = program->addShaderFromSourceCode(QOpenGLShader::Vertex,
- "attribute highp vec4 vertex;\n"
- "attribute highp vec2 texCoord;\n"
- "uniform highp mat4 matrix;\n"
- "varying highp vec2 texc;\n"
- "void main(void)\n"
- "{\n"
- " gl_Position = matrix * vertex;\n"
- " texc = texCoord;\n"
- "}");
- // TODO rewrite this monster
- if (!context()->isOpenGLES() &&
- context()->versionFunctions<QOpenGLFunctions_4_0_Core>() != nullptr) {
- bool frag = program->addShaderFromSourceCode(QOpenGLShader::Fragment,
- "#version 400\n"
- "uniform sampler2D gradient;\n"
- "uniform sampler2D tex;\n"
- "uniform mediump vec4 color;\n"
- "uniform highp float gradientScaler;\n"
- "uniform highp float maxIterations;\n"
- "varying highp vec2 texc;\n"
- "vec4 colorize(float pos) {\n"
- " if (pos >= maxIterations) {\n"
- " return vec4(0.0, 0.0, 0.0, 1.0);\n"
- " } else {\n"
- " return texture2D(gradient, vec2(pos * gradientScaler, 0.0));\n"
- " }\n"
- "}\n"
- "void main(void)\n"
- "{\n"
- " vec2 size = textureSize(tex, 0);\n"
- " size = vec2(256.0, 256.0);\n"
- " vec2 accPoint = texc * size;\n"
- " vec2 ip = floor(accPoint);\n"
- " vec2 fp = fract(accPoint);\n"
- " vec4 inter = textureGather(tex, ip / size, 0);\n"
- " vec4 col1 = colorize(inter.x);\n"
- " vec4 col2 = colorize(inter.y);\n"
- " vec4 col3 = colorize(inter.z);\n"
- " vec4 col4 = colorize(inter.w);\n"
- " vec4 col = mix(mix(col4, col3, fp.x), mix(col1, col2, fp.x), fp.y);\n"
- " gl_FragColor = col;\n"
- // " gl_FragColor = gl_FragColor * texture2D(tex, texc);\n"
- // " float v = texture2D(tex, texc).r;\n"
- // " gl_FragColor = vec4(v, 1.0 - v, v*v, 1);\n"
- // " gl_FragColor.g = 0.3;\n"
- "}");
- }
- else {
- bool frag = program->addShaderFromSourceCode(QOpenGLShader::Fragment,
- // "#version 110\n"
- "uniform sampler2D gradient;\n"
- "uniform sampler2D tex;\n"
- "uniform mediump vec4 color;\n"
- "uniform highp float gradientScaler;\n"
- "uniform highp float maxIterations;\n"
- "varying highp vec2 texc;\n"
- "void main(void)\n"
- "{\n"
- " highp float v = texture2D(tex, texc).r;\n"
- " if (v >= maxIterations) {\n"
- " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
- " } else {\n"
- " gl_FragColor = texture2D(gradient, vec2(v * gradientScaler, 0.0));\n"
- " }\n"
- // " gl_FragColor = gl_FragColor * texture2D(tex, texc);\n"
- // " float v = texture2D(tex, texc).r;\n"
- // " gl_FragColor = vec4(v, 1.0 - v, v*v, 1);\n"
- // " gl_FragColor.g = 0.3;\n"
- "}");
- }
- //program.link();
- bool bound = program->bind();
- bound = renderTextures->bind();
- int vertexLoc = program->attributeLocation("vertex");
- int texCoordsLoc = program->attributeLocation("texCoord");
- int colorLocation = program->uniformLocation("color");
- int texLoc = program->uniformLocation("tex");
- int gradLoc = program->uniformLocation("gradient");
- int gradientScaler = program->uniformLocation("gradientScaler");
- int maxIterations = program->uniformLocation("maxIterations");
- program->setUniformValue(gradientScaler, 0.005f);
- program->setUniformValue(maxIterations, 250.0f);
- auto& gle = *this->context()->extraFunctions();
- gl.glGenTextures(1, &tileTexture);
- gl.glBindTexture(GL_TEXTURE_2D, tileTexture);
- gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- gl.glBindTexture(GL_TEXTURE_2D, 0);
- gl.glGenFramebuffers(1, &tileFramebuffer);
- gl.glBindFramebuffer(GL_FRAMEBUFFER, tileFramebuffer);
- gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tileTexture, 0);
- GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
- gle.glDrawBuffers(1, drawBuffers);
- if(gl.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- printf("error intitializing framebuffer\n");
- }
- gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
- unsigned char pix[] = { 255, 0, 0, 0, 255, 0, 0, 0, 255 };
- GLuint id;
- gl.glEnable(GL_TEXTURE_2D);
- gl.glGenTextures(1, &id);
- gl.glBindTexture(GL_TEXTURE_2D, id);
- gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 3, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<char*> (pix));
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl.glBindTexture(GL_TEXTURE_2D, 0);
- gradientTextureId = id;
- gl.glDisable(GL_DEPTH_TEST);
- //gl3.glBindSampler(0, id);
- }
- void EscapeTimeVisualWidget::resizeGL(int w, int h)
- {
- auto& gl = *this->context()->functions();
- float pixelRatio = this->devicePixelRatioF();
- //pixelRatio = 1.0 / 32;
- float newW = w * pixelRatio;
- float newH = h * pixelRatio;
- setResolutionX(newW);
- setResolutionY(newH);
- gl.glViewport(0, 0, newW, newH);
- QMatrix4x4 pmvMatrix;
- pmvMatrix.ortho(QRectF{ 0, 0, newW, newH });
- int matrixLocation = program->uniformLocation("matrix");
- int rtMatrixLocation = renderTextures->uniformLocation("matrix");
- int jMatrixLocation = juliaPreviewer->uniformLocation("matrix");
- program->setUniformValue(matrixLocation, pmvMatrix);
- renderTextures->setUniformValue(rtMatrixLocation, pmvMatrix);
- juliaPreviewer->setUniformValue(jMatrixLocation, pmvMatrix);
- }
- void EscapeTimeVisualWidget::paintGL(void)
- {
- if (gradientNeedsUpdate)
- updateGradient();
- /*ETVImage etvi{ *this };
- auto& gl = *this->context()->functions();
- gl.glClearColor(0.0, 0.2, 0.0, 1.0);
- gl.glClear(GL_COLOR_BUFFER_BIT);
- etvi.draw(100, 100, 700, 700);*/
- }
- void EscapeTimeVisualWidget::drawJulia(float jx, float jy, QRectF area)
- {
- juliaPreviewer->bind();
- int gradLoc = juliaPreviewer->uniformLocation("gradient");
- int gradientScaler = juliaPreviewer->uniformLocation("gradientScaler");
- int juliaX = juliaPreviewer->uniformLocation("juliaX");
- int juliaY = juliaPreviewer->uniformLocation("juliaY");
- int vertexLoc = juliaPreviewer->attributeLocation("vertex");
- int texCoordsLoc = juliaPreviewer->attributeLocation("texCoord");
- int maxIterLoc = juliaPreviewer->attributeLocation("maxIterations");
- const float x = area.x();
- const float y = area.y();
- const float w = area.width();
- const float h = area.height();
- GLfloat const vertices[] = {
- x, y, 0.0f,
- x, y + h, 0.0f,
- x + w, y, 0.0f,
- x + w, y + h, 0.0f,
- };
- GLfloat const texCoords[] = {
- 0, 0,
- 0, 1,
- 1, 0,
- 1, 1,
- };
- auto& gl = *this->context()->functions();
- gl.glEnable(GL_TEXTURE_2D);
- gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
- juliaPreviewer->setAttributeArray(vertexLoc, vertices, 3);
- juliaPreviewer->setAttributeArray(texCoordsLoc, texCoords, 2);
- juliaPreviewer->enableAttributeArray(vertexLoc);
- juliaPreviewer->enableAttributeArray(texCoordsLoc);
- juliaPreviewer->setUniformValue(gradientScaler, 1.0f / float(gradientTextureMax));
- juliaPreviewer->setUniformValue(maxIterLoc, float(250));
- juliaPreviewer->setUniformValue(juliaX, float(jx));
- juliaPreviewer->setUniformValue(juliaY, float(jy));
- gl.glUniform1i(gradLoc, 0);
- gl.glActiveTexture(GL_TEXTURE0);
- gl.glBindTexture(GL_TEXTURE_2D, gradientTextureId);
- gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- juliaPreviewer->disableAttributeArray(vertexLoc);
- juliaPreviewer->disableAttributeArray(texCoordsLoc);
- //juliaPreviewer->release();
- //program->bind();
- }
- void EscapeTimeVisualWidget::setMaxIterationCutoff(float maxIter)
- {
- this->maxIterations = maxIter;
- }
- void EscapeTimeVisualWidget::updateGradient(void)
- {
- auto& gl = *this->context()->functions();
- int len = 512;
- if (gradient.getPoints().size() > 25) {
- len = 2048;
- }
- else if (gradient.getPoints().size() > 7) {
- len = 1024;
- }
- std::unique_ptr<uint8_t[]> pixels = std::make_unique<uint8_t[]>(len * 3);
- for (int i = 0; i < len; i++) {
- RGBColor c = gradient.get(gradient.getMax() * i / len);
- pixels[i * 3] = c.r;
- pixels[i * 3 + 1] = c.g;
- pixels[i * 3 + 2] = c.b;
- }
- gl.glEnable(GL_TEXTURE_2D);
- gl.glBindTexture(GL_TEXTURE_2D, gradientTextureId);
- gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, len, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<unsigned char*> (pixels.get()));
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl.glBindTexture(GL_TEXTURE_2D, 0);
- this->gradientTextureMax = gradient.getMax();
- gradientNeedsUpdate = false;
- }
- void EscapeTimeVisualWidget::setResolutionX(int w)
- {
- resolutionX = w;
- }
- void EscapeTimeVisualWidget::setResolutionY(int h)
- {
- resolutionY = h;
- }
- int EscapeTimeVisualWidget::getResolutionX(void) const
- {
- return resolutionX;
- }
- int EscapeTimeVisualWidget::getResolutionY(void) const
- {
- return resolutionY;
- }
|