diff --git a/Source/EmberCL/EmberCLStructs.h b/Source/EmberCL/EmberCLStructs.h index dd16b8d..fa74954 100644 --- a/Source/EmberCL/EmberCLStructs.h +++ b/Source/EmberCL/EmberCLStructs.h @@ -19,16 +19,17 @@ namespace EmberCLns static string ConstantDefinesString(bool doublePrecision) { ostringstream os; + os << "#if defined(cl_amd_fp64)\n"//AMD extension available? + " #pragma OPENCL EXTENSION cl_amd_fp64 : enable\n" + "#endif\n" + "#if defined(cl_khr_fp64)\n"//Khronos extension available? + " #pragma OPENCL EXTENSION cl_khr_fp64 : enable\n" + "#endif\n" + "#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable\n";//Only supported on nVidia. if (doublePrecision) { - os << "#if defined(cl_amd_fp64)\n"//AMD extension available? - " #pragma OPENCL EXTENSION cl_amd_fp64 : enable\n" - "#endif\n" - "#if defined(cl_khr_fp64)\n"//Khronos extension available? - " #pragma OPENCL EXTENSION cl_khr_fp64 : enable\n" - "#endif\n" - "#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable\n"//Only supported on nVidia. + os << "typedef long intPrec;\n" "typedef uint atomi;\n"//Same size as real_bucket_t, always 4 bytes. "typedef double real_t;\n" diff --git a/Source/Fractorium/FractoriumPch.h b/Source/Fractorium/FractoriumPch.h index d979ca2..5c46c19 100644 --- a/Source/Fractorium/FractoriumPch.h +++ b/Source/Fractorium/FractoriumPch.h @@ -70,7 +70,8 @@ #include #include #include -#include +#include +//#include #include #include #include diff --git a/Source/Fractorium/GLEmberController.cpp b/Source/Fractorium/GLEmberController.cpp index 0d49052..ae81e89 100644 --- a/Source/Fractorium/GLEmberController.cpp +++ b/Source/Fractorium/GLEmberController.cpp @@ -128,6 +128,7 @@ typename v3T GLEmberController::SnapToGrid(v3T& vec) v3T ret; ret.x = glm::round(vec.x / GridStep) * GridStep; ret.y = glm::round(vec.y / GridStep) * GridStep; + ret.z = vec.z; return ret; } @@ -185,9 +186,17 @@ typename v3T GLEmberController::WindowToWorld(v3T& v, bool flip) template <> void GLEmberController::QueryVMP() { +#ifndef USE_GLSL m_GL->glGetIntegerv(GL_VIEWPORT, glm::value_ptr(m_Viewport)); m_GL->glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(m_Modelview)); m_GL->glGetFloatv(GL_PROJECTION_MATRIX, glm::value_ptr(m_Projection)); +#else + m_Viewport = m_GL->m_Viewport; + glm::tmat4x4 tempmat = glm::make_mat4(m_GL->m_ModelViewMatrix.data()); + m_Modelview = tempmat; + tempmat = glm::make_mat4(m_GL->m_ProjMatrix.data()); + m_Projection = tempmat; +#endif } #ifdef DO_DOUBLE @@ -198,9 +207,17 @@ void GLEmberController::QueryVMP() template <> void GLEmberController::QueryVMP() { +#ifndef USE_GLSL m_GL->glGetIntegerv(GL_VIEWPORT, glm::value_ptr(m_Viewport)); m_GL->glGetDoublev(GL_MODELVIEW_MATRIX, glm::value_ptr(m_Modelview)); m_GL->glGetDoublev(GL_PROJECTION_MATRIX, glm::value_ptr(m_Projection)); +#else + m_Viewport = m_GL->m_Viewport; + glm::tmat4x4 tempmat = glm::make_mat4(m_GL->m_ModelViewMatrix.data()); + m_Modelview = tempmat; + tempmat = glm::make_mat4(m_GL->m_ProjMatrix.data()); + m_Projection = tempmat; +#endif } #endif @@ -208,23 +225,27 @@ void GLEmberController::QueryVMP() /// Template specialization for multiplying the current matrix /// by an m4. /// +#ifndef USE_GLSL template <> void GLEmberController::MultMatrix(tmat4x4& mat) { m_GL->glMultMatrixf(glm::value_ptr(mat)); } +#endif #ifdef DO_DOUBLE /// /// Template specialization for multiplying the current matrix /// by an m4. /// +#ifndef USE_GLSL template <> void GLEmberController::MultMatrix(tmat4x4& mat) { m_GL->glMultMatrixd(glm::value_ptr(mat)); } #endif +#endif /// /// Query the matrices currently being used. @@ -238,20 +259,7 @@ void GLEmberController::QueryMatrices(bool print) if (renderer) { - double unitX = std::abs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0; - double unitY = std::abs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0; - m_GL->glMatrixMode(GL_PROJECTION); - m_GL->glPushMatrix(); - m_GL->glLoadIdentity(); - m_GL->glOrtho(-unitX, unitX, -unitY, unitY, -1, 1); - m_GL->glMatrixMode(GL_MODELVIEW); - m_GL->glPushMatrix(); - m_GL->glLoadIdentity(); QueryVMP(); - m_GL->glMatrixMode(GL_PROJECTION); - m_GL->glPopMatrix(); - m_GL->glMatrixMode(GL_MODELVIEW); - m_GL->glPopMatrix(); if (print) { diff --git a/Source/Fractorium/GLEmberController.h b/Source/Fractorium/GLEmberController.h index 78443c4..89f6a87 100644 --- a/Source/Fractorium/GLEmberController.h +++ b/Source/Fractorium/GLEmberController.h @@ -34,6 +34,8 @@ class GLWidget; class Fractorium; template class FractoriumEmberController; +#define USE_GLSL 1 + /// /// GLEmberControllerBase serves as a non-templated base class with virtual /// functions which will be overridden in a derived class that takes a template parameter. @@ -124,7 +126,9 @@ private: v3T SnapToNormalizedAngle(v3T& vec, uint divisions); v3T WindowToWorld(v3T& v, bool flip); void QueryVMP(); +#ifndef USE_GLSL void MultMatrix(m4T& mat); +#endif T m_CenterDownX; T m_CenterDownY; @@ -147,5 +151,6 @@ private: Xform* m_SelectedXform; FractoriumEmberController* m_FractoriumEmberController; T GridStep; + vector m_Verts;//Can't make this T because GLSL only works with floats. }; diff --git a/Source/Fractorium/GLWidget.cpp b/Source/Fractorium/GLWidget.cpp index 8d556f4..e90c426 100644 --- a/Source/Fractorium/GLWidget.cpp +++ b/Source/Fractorium/GLWidget.cpp @@ -2,6 +2,37 @@ #include "GLWidget.h" #include "Fractorium.h" +#ifdef USE_GLSL + static const char* vertexShaderSource = + "attribute vec4 posattr;\n" + "uniform mat4 matrix;\n" + "void main() {\n" + " gl_Position = matrix * posattr;\n" + "}\n"; + + static const char* fragmentShaderSource = + "uniform vec4 mycolor;\n" + "void main() {\n" + " gl_FragColor = mycolor;\n" + "}\n"; + + static const char* quadVertexShaderSource = + "attribute vec4 posattr;\n" + "uniform mat4 matrix;\n" + "varying vec4 texcoord;\n" + "void main() {\n" + " gl_Position = matrix * posattr;\n" + " texcoord = posattr;\n" + "}\n"; + + static const char* quadFragmentShaderSource = + "uniform sampler2D quadtex;\n" + "varying vec4 texcoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(quadtex, texcoord.st);\n" + "}\n"; +#endif + /// /// Constructor which passes parent widget to the base and initializes OpenGL profile. /// This will need to change in the future to implement all drawing as shader programs. @@ -10,11 +41,13 @@ GLWidget::GLWidget(QWidget* p) : QOpenGLWidget(p) { +#ifndef USE_GLSL QSurfaceFormat qsf; qsf.setSwapInterval(1);//Vsync. qsf.setSwapBehavior(QSurfaceFormat::DoubleBuffer); qsf.setVersion(2, 0); setFormat(qsf); +#endif } /// @@ -76,6 +109,7 @@ void GLWidget::InitGL() /// void GLWidget::DrawQuad() { +#ifndef USE_GLSL glEnable(GL_TEXTURE_2D); auto renderer = m_Fractorium->m_Controller->Renderer(); auto finalImage = m_Fractorium->m_Controller->FinalImage(); @@ -91,7 +125,6 @@ void GLWidget::DrawQuad() if (m_TexWidth == m_Fractorium->m_Controller->FinalRasW() && m_TexHeight == m_Fractorium->m_Controller->FinalRasH() && ((m_TexWidth * m_TexHeight) == GLint(finalImage->size()))) - //if (m_TexWidth == scaledW && m_TexHeight == scaledH && ((m_TexWidth * m_TexHeight) == GLint(finalImage->size()))) { glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -121,6 +154,40 @@ void GLWidget::DrawQuad() } glDisable(GL_TEXTURE_2D); +#else + this->glEnable(GL_TEXTURE_2D); + this->glActiveTexture(GL_TEXTURE0); + auto renderer = m_Fractorium->m_Controller->Renderer(); + auto finalImage = m_Fractorium->m_Controller->FinalImage(); + + //Ensure all allocation has taken place first. + if (m_OutputTexID != 0 && finalImage && !finalImage->empty()) + { + glBindTexture(GL_TEXTURE_2D, m_OutputTexID);//The texture to draw to. + auto scaledW = std::ceil(width() * devicePixelRatioF()); + auto scaledH = std::ceil(height() * devicePixelRatioF()); + + //Only draw if the dimensions match exactly. + if (m_TexWidth == m_Fractorium->m_Controller->FinalRasW() && + m_TexHeight == m_Fractorium->m_Controller->FinalRasH() && + ((m_TexWidth * m_TexHeight) == GLint(finalImage->size()))) + { + //Copy data from CPU to OpenGL if using a CPU renderer. This is not needed when using OpenCL. + if (renderer->RendererType() == eRendererType::CPU_RENDERER) + this->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_TexWidth, m_TexHeight, GL_RGBA, GL_FLOAT, finalImage->data()); + + m_QuadProgram->bind(); + this->glVertexAttribPointer(m_TexturePosAttr, 2, GL_FLOAT, GL_FALSE, 0, m_TexVerts.data()); + this->glEnableVertexAttribArray(0); + this->glDrawArrays(GL_TRIANGLE_STRIP, 0, 5); + this->glDisableVertexAttribArray(0); + m_QuadProgram->release(); + } + } + + this->glBindTexture(GL_TEXTURE_2D, 0);//Stop using this texture. + this->glDisable(GL_TEXTURE_2D); +#endif } /// @@ -210,13 +277,82 @@ GLuint GLWidget::OutputTexID() { return m_OutputTexID; } /// void GLWidget::initializeGL() { +#ifdef USE_GLSL + + if (!m_Init && m_Fractorium) + { + initializeOpenGLFunctions(); + + if (!m_Program) + { + m_Program = new QOpenGLShaderProgram(this); + + if (!m_Program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) + { + QMessageBox::critical(m_Fractorium, "Shader Error", "Error compiling affine vertex source."); + QApplication::exit(1); + } + + if (!m_Program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource)) + { + QMessageBox::critical(m_Fractorium, "Shader Error", "Error compiling affine fragment source."); + QApplication::exit(1); + } + + if (!m_Program->link()) + { + QMessageBox::critical(m_Fractorium, "Shader Error", "Error linking affine source."); + QApplication::exit(1); + } + + m_PosAttr = m_Program->attributeLocation("posattr"); + m_ColAttr = m_Program->uniformLocation("mycolor"); + m_MatrixUniform = m_Program->uniformLocation("matrix"); + } + + if (!m_QuadProgram) + { + m_QuadProgram = new QOpenGLShaderProgram(this); + + if (!m_QuadProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, quadVertexShaderSource)) + { + QMessageBox::critical(m_Fractorium, "Shader Error", "Error compiling image texture vertex source."); + QApplication::exit(1); + } + + if (!m_QuadProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, quadFragmentShaderSource)) + { + QMessageBox::critical(m_Fractorium, "Shader Error", "Error compiling image texture fragment source."); + QApplication::exit(1); + } + + if (!m_QuadProgram->link()) + { + QMessageBox::critical(m_Fractorium, "Shader Error", "Error linking image texture source."); + QApplication::exit(1); + } + + m_TexturePosAttr = m_QuadProgram->attributeLocation("posattr"); + m_TextureUniform = m_QuadProgram->uniformLocation("quadtex"); + m_TextureMatrixUniform = m_QuadProgram->uniformLocation("matrix"); + m_TextureProjMatrix.ortho(0, 1, 1, 0, -1, 1); + m_QuadProgram->bind(); + m_QuadProgram->setUniformValue(m_TextureUniform, 0); + m_QuadProgram->setUniformValue(m_TextureMatrixUniform, m_TextureProjMatrix); + m_QuadProgram->release(); + } + +#else + if (!m_Init && initializeOpenGLFunctions() && m_Fractorium) { - glClearColor(0.0, 0.0, 0.0, 1.0); - glEnable(GL_TEXTURE_2D); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); - glDisable(GL_TEXTURE_2D); - m_Fractorium->m_WidthSpin->setMaximum(m_MaxTexSize); +#endif + this->glClearColor(0.0, 0.0, 0.0, 1.0); + this->glDisable(GL_DEPTH_TEST);//This will remain disabled for the duration of the program. + this->glEnable(GL_TEXTURE_2D); + this->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); + this->glDisable(GL_TEXTURE_2D); + m_Fractorium->m_WidthSpin->setMaximum(m_MaxTexSize);//This should also apply to the final render dialog.//TODO m_Fractorium->m_HeightSpin->setMaximum(m_MaxTexSize); } } @@ -250,32 +386,39 @@ void GLWidget::paintGL() bool post = m_Fractorium->ui.PostAffineGroupBox->isChecked(); float unitX = std::abs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f; float unitY = std::abs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f; - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glEnable(GL_LINE_SMOOTH); - glEnable(GL_POINT_SMOOTH); + this->glEnable(GL_BLEND); + this->glEnable(GL_LINE_SMOOTH); + this->glEnable(GL_POINT_SMOOTH); #if defined (__APPLE__) || defined(MACOSX) - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_COLOR); + this->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_COLOR); #else - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + this->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); #endif - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(-unitX, unitX, -unitY, unitY, -1, 1);//Projection matrix: OpenGL camera is always centered, just move the ember internally inside the renderer. - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glDisable(GL_DEPTH_TEST); +#ifndef USE_GLSL + this->glMatrixMode(GL_PROJECTION); + this->glPushMatrix(); + this->glLoadIdentity(); + this->glOrtho(-unitX, unitX, -unitY, unitY, -1, 1);//Projection matrix: OpenGL camera is always centered, just move the ember internally inside the renderer. + this->glMatrixMode(GL_MODELVIEW); + this->glPushMatrix(); + this->glLoadIdentity(); controller->GLController()->DrawAffines(pre, post); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_POINT_SMOOTH); + this->glMatrixMode(GL_PROJECTION); + this->glPopMatrix(); + this->glMatrixMode(GL_MODELVIEW); + this->glPopMatrix(); +#else + m_Program->bind(); + m_ProjMatrix.setToIdentity(); + m_ProjMatrix.ortho(-unitX, unitX, -unitY, unitY, -1, 1);//Projection matrix: OpenGL camera is always centered, just move the ember internally inside the renderer. + m_ModelViewMatrix.setToIdentity(); + //this->DrawUnitSquare(); + controller->GLController()->DrawAffines(pre, post); + m_Program->release(); +#endif + this->glDisable(GL_BLEND); + this->glDisable(GL_LINE_SMOOTH); + this->glDisable(GL_POINT_SMOOTH); m_Drawing = false; } } @@ -290,7 +433,6 @@ void GLEmberController::DrawImage() auto ember = m_FractoriumEmberController->CurrentEmber(); m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0); m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - m_GL->glDisable(GL_DEPTH_TEST); renderer->EnterFinalAccum();//Lock, may not be necessary, but just in case. renderer->EnterResize(); @@ -370,15 +512,25 @@ void GLEmberController::DrawAffines(bool pre, bool post) if (dragging)//Draw large yellow dot on select or drag. { m_GL->glPointSize(6.0f * m_GL->devicePixelRatioF()); +#ifndef USE_GLSL m_GL->glBegin(GL_POINTS); m_GL->glColor4f(1.0f, 1.0f, 0.5f, 1.0f); m_GL->glVertex2f(m_DragHandlePos.x, m_DragHandlePos.y); m_GL->glEnd(); +#else + GLfloat vertices[] =//Should these be of type T?//TODO + { + m_DragHandlePos.x, m_DragHandlePos.y + }; + QVector4D col(1.0f, 1.0f, 0.5f, 1.0f); + m_GL->DrawPointOrLine(col, vertices, 1, GL_POINTS); +#endif m_GL->glPointSize(1.0f * m_GL->devicePixelRatioF());//Restore point size. } else if (m_DragState == eDragState::DragSelect) { m_GL->glLineWidth(2.0f * m_GL->devicePixelRatioF()); +#ifndef USE_GLSL m_GL->glBegin(GL_LINES); m_GL->glColor4f(0.0f, 0.0f, 1.0f, 1.0f); m_GL->glVertex2f(m_MouseDownWorldPos.x, m_MouseDownWorldPos.y);//UL->UR @@ -390,15 +542,39 @@ void GLEmberController::DrawAffines(bool pre, bool post) m_GL->glVertex2f(m_MouseWorldPos.x, m_MouseDownWorldPos.y);//UR->LR m_GL->glVertex2f(m_MouseWorldPos.x, m_MouseWorldPos.y); m_GL->glEnd(); +#else + GLfloat vertices[] =//Should these be of type T?//TODO + { + m_MouseDownWorldPos.x, m_MouseDownWorldPos.y,//UL->UR + m_MouseWorldPos.x, m_MouseDownWorldPos.y, + m_MouseDownWorldPos.x, m_MouseWorldPos.y,//LL->LR + m_MouseWorldPos.x, m_MouseWorldPos.y, + m_MouseDownWorldPos.x, m_MouseDownWorldPos.y,//UL->LL + m_MouseDownWorldPos.x, m_MouseWorldPos.y, + m_MouseWorldPos.x, m_MouseDownWorldPos.y,//UR->LR + m_MouseWorldPos.x, m_MouseWorldPos.y + }; + QVector4D col(0.0f, 0.0f, 1.0f, 1.0f); + m_GL->DrawPointOrLine(col, vertices, 8, GL_LINES); +#endif m_GL->glLineWidth(1.0f * m_GL->devicePixelRatioF()); } else if (m_HoverType != eHoverType::HoverNone && m_HoverXform == m_SelectedXform)//Draw large turquoise dot on hover if they are hovering over the selected xform. { m_GL->glPointSize(6.0f * m_GL->devicePixelRatioF()); +#ifndef USE_GLSL m_GL->glBegin(GL_POINTS); m_GL->glColor4f(0.5f, 1.0f, 1.0f, 1.0f); m_GL->glVertex2f(m_HoverHandlePos.x, m_HoverHandlePos.y); m_GL->glEnd(); +#else + GLfloat vertices[] =//Should these be of type T?//TODO + { + m_HoverHandlePos.x, m_HoverHandlePos.y + }; + QVector4D col(0.5f, 1.0f, 1.0f, 1.0f); + m_GL->DrawPointOrLine(col, vertices, 1, GL_POINTS); +#endif m_GL->glPointSize(1.0f * m_GL->devicePixelRatioF()); } } @@ -747,6 +923,37 @@ void GLWidget::wheelEvent(QWheelEvent* e) //Do not call QOpenGLWidget::wheelEvent(e) because this should only affect the scale and not the position of the scroll bars. } +/// +/// Wrapper around drawing a simple primitive, like a point or line, using a GLSL program. +/// +/// The color to draw with +/// The vertices to use +/// The type of primitive to draw, such as GL_POINT or GL_LINES +void GLWidget::DrawPointOrLine(const QVector4D& col, const std::vector& vertices, int drawType) +{ + DrawPointOrLine(col, vertices.data(), vertices.size() / 2, drawType); +} + +/// +/// Wrapper around drawing a simple primitive, like a point or line, using a GLSL program. +/// +/// The color to draw with +/// The vertices to use +/// The number of verticies. This is usually the size of vertices / 2. +/// The type of primitive to draw, such as GL_POINT or GL_LINES +void GLWidget::DrawPointOrLine(const QVector4D& col, const GLfloat* vertices, int size, int drawType) +{ +#ifdef USE_GLSL + m_ModelViewProjectionMatrix = m_ProjMatrix * m_ModelViewMatrix; + m_Program->setUniformValue(m_ColAttr, col); + m_Program->setUniformValue(m_MatrixUniform, m_ModelViewProjectionMatrix); + this->glVertexAttribPointer(m_PosAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices); + this->glEnableVertexAttribArray(0); + this->glDrawArrays(drawType, 0, size); + this->glDisableVertexAttribArray(0); +#endif +} + /// /// Set the dimensions of the drawing area. /// This will be called from the main window's SyncSizes() function. @@ -775,6 +982,7 @@ bool GLWidget::Allocate(bool force) auto h = m_Fractorium->m_Controller->FinalRasH(); bool doResize = force || m_TexWidth != w || m_TexHeight != h; bool doIt = doResize || m_OutputTexID == 0; +#ifndef USE_GLSL if (doIt) { @@ -806,6 +1014,39 @@ bool GLWidget::Allocate(bool force) glDisable(GL_TEXTURE_2D); } +#else + + if (doIt) + { + m_TexWidth = GLint(w); + m_TexHeight = GLint(h); + this->glEnable(GL_TEXTURE_2D); + + if (doResize) + Deallocate(); + + this->glActiveTexture(GL_TEXTURE0); + this->glGenTextures(1, &m_OutputTexID); + this->glBindTexture(GL_TEXTURE_2D, m_OutputTexID); + this->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//Fractron had this as GL_LINEAR_MIPMAP_LINEAR for OpenCL and Cuda. + this->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + this->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + this->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); +#if defined (__APPLE__) || defined(MACOSX) + this->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, m_TexWidth, m_TexHeight, 0, GL_RGB, GL_FLOAT, nullptr); +#else + this->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_TexWidth, m_TexHeight, 0, GL_RGBA, GL_FLOAT, nullptr); +#endif + alloc = true; + } + + if (alloc) + { + this->glBindTexture(GL_TEXTURE_2D, 0); + this->glDisable(GL_TEXTURE_2D); + } + +#endif return m_OutputTexID != 0; } @@ -819,8 +1060,8 @@ bool GLWidget::Deallocate() if (m_OutputTexID != 0) { - glBindTexture(GL_TEXTURE_2D, m_OutputTexID); - glDeleteTextures(1, &m_OutputTexID); + this->glBindTexture(GL_TEXTURE_2D, m_OutputTexID); + this->glDeleteTextures(1, &m_OutputTexID); m_OutputTexID = 0; deleted = true; } @@ -836,7 +1077,10 @@ void GLWidget::SetViewport() { if (m_Init && (m_ViewWidth != m_TexWidth || m_ViewHeight != m_TexHeight)) { - glViewport(0, 0, GLint(m_TexWidth), GLint(m_TexHeight)); + this->glViewport(0, 0, GLint(m_TexWidth), GLint(m_TexHeight)); +#ifdef USE_GLSL + m_Viewport = glm::ivec4(0, 0, m_TexWidth, m_TexHeight); +#endif m_ViewWidth = m_TexWidth; m_ViewHeight = m_TexHeight; } @@ -868,6 +1112,7 @@ bool GLEmberController::SizesMatch() void GLWidget::DrawUnitSquare() { glLineWidth(1.0f * devicePixelRatioF()); +#ifndef USE_GLSL glBegin(GL_LINES); glColor4f(1.0f, 1.0f, 1.0f, 0.25f); glVertex2f(-1, -1); @@ -885,6 +1130,35 @@ void GLWidget::DrawUnitSquare() glVertex2f( 0, -1); glVertex2f( 0, 1); glEnd(); +#else + GLfloat vertices[] =//Should these be of type T?//TODO + { + -1, -1, + 1, -1, + -1, 1, + 1, 1, + -1, -1, + -1, 1, + 1, -1, + 1, 1 + }; + QVector4D col(1.0f, 1.0f, 1.0f, 0.25f); + DrawPointOrLine(col, vertices, 8, GL_LINES); + GLfloat vertices2[] =//Should these be of type T?//TODO + { + -1, 0, + 1, 0 + }; + QVector4D col2(1.0f, 0.0f, 0.0f, 0.5f); + DrawPointOrLine(col2, vertices2, 2, GL_LINES); + GLfloat vertices3[] =//Should these be of type T?//TODO + { + 0, -1, + 0, 1 + }; + QVector4D col3(0.0f, 1.0f, 0.0f, 0.5f); + DrawPointOrLine(col3, vertices3, 2, GL_LINES); +#endif } /// @@ -909,11 +1183,12 @@ void GLEmberController::DrawGrid() int xsteps = std::ceil(std::abs(xHigh - xLow) / GridStep);//Need these because sometimes the float value never reaches the max and it gets stuck in an infinite loop. int ysteps = std::ceil(std::abs(yHigh - yLow) / GridStep); Affine2D temp; + m_GL->glLineWidth(1.0f * m_GL->devicePixelRatioF()); +#ifndef USE_GLSL m4T mat = (temp * scale).ToMat4RowMajor(); m_GL->glPushMatrix(); m_GL->glLoadIdentity(); MultMatrix(mat); - m_GL->glLineWidth(1.0f * m_GL->devicePixelRatioF()); m_GL->glBegin(GL_LINES); m_GL->glColor4f(0.5f, 0.5f, 0.5f, alpha); @@ -944,6 +1219,60 @@ void GLEmberController::DrawGrid() m_GL->glColor4f(0.0f, 0.0f, 0.0f, 1.0f); m_GL->glEnd(); m_GL->glPopMatrix(); +#else + m4T mat = (temp * scale).ToMat4ColMajor(); + glm::tmat4x4 tempmat4 = mat; + m_GL->m_ModelViewMatrix = QMatrix4x4(glm::value_ptr(tempmat4)); + m_GL->glLineWidth(1.0f * m_GL->devicePixelRatioF()); + m_Verts.clear(); + + for (float fx = xLow, i = 0; fx <= xHigh && i < xsteps; fx += GridStep, i++) + { + m_Verts.push_back(fx); + m_Verts.push_back(yLow); + m_Verts.push_back(fx); + m_Verts.push_back(yHigh); + } + + for (float fy = yLow, i = 0; fy < yHigh && i < ysteps; fy += GridStep, i++) + { + m_Verts.push_back(xLow); + m_Verts.push_back(fy); + m_Verts.push_back(xHigh); + m_Verts.push_back(fy); + } + + QVector4D col(0.5f, 0.5f, 0.5f, alpha); + m_GL->DrawPointOrLine(col, m_Verts, GL_LINES); + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(xHigh); + m_Verts.push_back(0.0f); + col = QVector4D(1.0f, 0.0f, 0.0f, alpha); + m_GL->DrawPointOrLine(col, m_Verts, GL_LINES); + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(xLow); + m_Verts.push_back(0.0f); + col = QVector4D(0.5f, 0.0f, 0.0f, alpha); + m_GL->DrawPointOrLine(col, m_Verts, GL_LINES); + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(yHigh); + col = QVector4D(0.0f, 1.0f, 0.0f, alpha); + m_GL->DrawPointOrLine(col, m_Verts, GL_LINES); + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(yLow); + col = QVector4D(0.0f, 0.5f, 0.0f, alpha); + m_GL->DrawPointOrLine(col, m_Verts, GL_LINES); +#endif } /// @@ -963,6 +1292,7 @@ void GLEmberController::DrawAffine(Xform* xform, bool pre, bool selected) auto size = ember->m_Palette.m_Entries.size(); auto color = ember->m_Palette.m_Entries[Clamp(xform->m_ColorX * size, 0, size - 1)]; auto& affine = pre ? xform->m_Affine : xform->m_Post; +#ifndef USE_GLSL //For some incredibly strange reason, even though glm and OpenGL use matrices with a column-major //data layout, nothing will work here unless they are flipped to row major order. This is how it was //done in Fractron. @@ -970,6 +1300,7 @@ void GLEmberController::DrawAffine(Xform* xform, bool pre, bool selected) m_GL->glPushMatrix(); m_GL->glLoadIdentity(); MultMatrix(mat); + //QueryMatrices(true); m_GL->glLineWidth(3.0f * m_GL->devicePixelRatioF());//One 3px wide, colored black, except green on x axis for post affine. m_GL->DrawAffineHelper(index, selected, pre, final, true); m_GL->glLineWidth(1.0f * m_GL->devicePixelRatioF());//Again 1px wide, colored white, to give a white middle with black outline effect. @@ -996,6 +1327,48 @@ void GLEmberController::DrawAffine(Xform* xform, bool pre, bool selected) m_GL->glColor4f(0.0f, 0.0f, 0.0f, 1.0f); m_GL->glEnd(); m_GL->glPopMatrix(); +#else + m4T mat = (affine * m_FractoriumEmberController->AffineScaleCurrentToLocked()).ToMat4ColMajor(); + glm::tmat4x4 tempmat4 = mat; + m_GL->m_ModelViewMatrix = QMatrix4x4(glm::value_ptr(tempmat4)); + //Need to figure out multmatrix calls here.//TODO + //QueryMatrices(true); + m_GL->glLineWidth(3.0f * m_GL->devicePixelRatioF());//One 3px wide, colored black, except green on x axis for post affine. + m_GL->DrawAffineHelper(index, selected, pre, final, true); + m_GL->glLineWidth(1.0f * m_GL->devicePixelRatioF());//Again 1px wide, colored white, to give a white middle with black outline effect. + m_GL->DrawAffineHelper(index, selected, pre, final, false); + m_GL->glPointSize(5.0f * m_GL->devicePixelRatioF());//Three black points, one in the center and two on the circle. Drawn big 5px first to give a black outline. + QVector4D col(0.0f, 0.0f, 0.0f, selected ? 1.0f : 0.5f); + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(1.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(1.0f); + m_GL->DrawPointOrLine(col, m_Verts, GL_POINTS); + // + m_GL->glLineWidth(2.0f * m_GL->devicePixelRatioF());//Draw lines again for y axis only, without drawing the circle, using the color of the selected xform. + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(1.0f); + col = QVector4D(color.r, color.g, color.b, 1.0f); + m_GL->DrawPointOrLine(col, m_Verts, GL_LINES); + // + m_GL->glPointSize(3.0f * m_GL->devicePixelRatioF());//Draw smaller white points, to give a black outline effect. + m_Verts.clear(); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(1.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(0.0f); + m_Verts.push_back(1.0f); + col = QVector4D(1.0f, 1.0f, 1.0f, selected ? 1.0f : 0.5f); + m_GL->DrawPointOrLine(col, m_Verts, GL_POINTS); + m_GL->m_ModelViewMatrix.setToIdentity(); +#endif } /// @@ -1012,6 +1385,7 @@ void GLWidget::DrawAffineHelper(int index, bool selected, bool pre, bool final, float px = 1.0f; float py = 0.0f; auto col = final ? m_Fractorium->m_FinalXformComboColor : m_Fractorium->m_XformComboColors[index % XFORM_COLOR_COUNT]; +#ifndef USE_GLSL glBegin(GL_LINES); //Circle part. @@ -1061,6 +1435,70 @@ void GLWidget::DrawAffineHelper(int index, bool selected, bool pre, bool final, glVertex2f(0.0f, 0.0f);//Y axis. glVertex2f(0.0f, 1.0f); glEnd(); +#else + QVector4D color; + + //Circle part. + if (!background) + { + color = QVector4D(col.redF(), col.greenF(), col.blueF(), 1.0f);//Draw pre affine transform with white. + } + else + { + color = QVector4D(0.0f, 0.0f, 0.0f, 1.0f);//Draw pre affine transform outline with white. + } + + m_Verts.clear(); + + if (selected) + { + for (size_t i = 1; i <= 64; i++)//The circle. + { + float theta = float(M_PI) * 2.0f * float(i % 64) / 64.0f; + float fx = std::cos(theta); + float fy = std::sin(theta); + m_Verts.push_back(px); + m_Verts.push_back(py); + m_Verts.push_back(fx); + m_Verts.push_back(fy); + px = fx; + py = fy; + } + } + + DrawPointOrLine(color, m_Verts, GL_LINES); + + //Lines from center to circle. + if (!background) + { + color = QVector4D(col.redF(), col.greenF(), col.blueF(), 1.0f); + } + else + { + if (pre) + color = QVector4D(0.0f, 0.0f, 0.0f, 1.0f);//Draw pre affine transform outline with white. + else + color = QVector4D(0.0f, 0.75f, 0.0f, 1.0f);//Draw post affine transform outline with green. + } + + //The lines from the center to the circle. + m_Verts.clear(); + m_Verts.push_back(0);//X axis. + m_Verts.push_back(0); + m_Verts.push_back(1); + m_Verts.push_back(0); + DrawPointOrLine(color, m_Verts, GL_LINES); + + if (background) + color = QVector4D(0.0f, 0.0f, 0.0f, 1.0f); + + m_Verts.clear(); + m_Verts.push_back(0);//Y axis. + m_Verts.push_back(0); + m_Verts.push_back(0); + m_Verts.push_back(1); + DrawPointOrLine(color, m_Verts, GL_LINES); +#endif } /// diff --git a/Source/Fractorium/GLWidget.h b/Source/Fractorium/GLWidget.h index 167aac6..5c2e21d 100644 --- a/Source/Fractorium/GLWidget.h +++ b/Source/Fractorium/GLWidget.h @@ -26,7 +26,12 @@ template class FractoriumEmberController; /// the main window and several of its members. /// This class uses a controller-based design similar to the main window. /// -class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_2_0//QOpenGLFunctions_3_2_Compatibility//QOpenGLFunctions_3_2_Core//, protected QOpenGLFunctions +class GLWidget : public QOpenGLWidget, protected +#ifdef USE_GLSL + QOpenGLFunctions_3_2_Core +#else + QOpenGLFunctions_2_0 +#endif { Q_OBJECT @@ -61,6 +66,9 @@ protected: virtual void mouseMoveEvent(QMouseEvent* e) override; virtual void wheelEvent(QWheelEvent* e) override; + void DrawPointOrLine(const QVector4D& col, const GLfloat* vertices, int size, int drawType); + void DrawPointOrLine(const QVector4D& col, const std::vector& vertices, int drawType); + private: void SetDimensions(int w, int h); bool Allocate(bool force = false); @@ -78,5 +86,29 @@ private: GLint m_ViewWidth = 0; GLint m_ViewHeight = 0; GLuint m_OutputTexID = 0; +#ifdef USE_GLSL + GLuint m_PosAttr; + GLuint m_ColAttr; + GLuint m_MatrixUniform; + GLuint m_TexturePosAttr; + GLuint m_TextureUniform; + GLuint m_TextureMatrixUniform; + glm::ivec4 m_Viewport; + QMatrix4x4 m_ProjMatrix; + QMatrix4x4 m_ModelViewMatrix; + QMatrix4x4 m_ModelViewProjectionMatrix; + QMatrix4x4 m_TextureProjMatrix; + vector m_Verts; + std::array m_TexVerts = + { + 0, 0, + 0, 1, + 1, 1, + 1, 0, + 0, 0 + }; + QOpenGLShaderProgram* m_Program = nullptr; + QOpenGLShaderProgram* m_QuadProgram = nullptr; +#endif Fractorium* m_Fractorium = nullptr; };