--User changes

-Convert OpenGL drawing code to use GLSL. Leave #define in until testing on multiple platforms is done.
 -Always use double precision extension defines in OpenCL programs, even if DP is not selected. This is because elliptic now always uses DP.
This commit is contained in:
Person 2018-03-27 21:32:10 -07:00
parent 90e7097d7f
commit ed74fd6a83
6 changed files with 540 additions and 55 deletions

View File

@ -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"

View File

@ -70,7 +70,8 @@
#include <QMimeData>
#include <QModelIndex>
#include <QMouseEvent>
#include <qopenglfunctions_2_0.h>
#include <QOpenGLFunctions_3_2_Core.h>
//#include <qopenglfunctions_2_0.h>
#include <QOpenGLWidget>
#include <QPainter>
#include <QPainterPath>

View File

@ -128,6 +128,7 @@ typename v3T GLEmberController<T>::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<T>::WindowToWorld(v3T& v, bool flip)
template <>
void GLEmberController<float>::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<float, glm::defaultp> 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<float>::QueryVMP()
template <>
void GLEmberController<double>::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<float, glm::defaultp> 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<double>::QueryVMP()
/// Template specialization for multiplying the current matrix
/// by an m4<float>.
/// </summary>
#ifndef USE_GLSL
template <>
void GLEmberController<float>::MultMatrix(tmat4x4<float, glm::defaultp>& mat)
{
m_GL->glMultMatrixf(glm::value_ptr(mat));
}
#endif
#ifdef DO_DOUBLE
/// <summary>
/// Template specialization for multiplying the current matrix
/// by an m4<double>.
/// </summary>
#ifndef USE_GLSL
template <>
void GLEmberController<double>::MultMatrix(tmat4x4<double, glm::defaultp>& mat)
{
m_GL->glMultMatrixd(glm::value_ptr(mat));
}
#endif
#endif
/// <summary>
/// Query the matrices currently being used.
@ -238,20 +259,7 @@ void GLEmberController<T>::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)
{

View File

@ -34,6 +34,8 @@ class GLWidget;
class Fractorium;
template <typename T> class FractoriumEmberController;
#define USE_GLSL 1
/// <summary>
/// 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<T>* m_SelectedXform;
FractoriumEmberController<T>* m_FractoriumEmberController;
T GridStep;
vector<float> m_Verts;//Can't make this T because GLSL only works with floats.
};

View File

@ -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
/// <summary>
/// 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
}
/// <summary>
@ -76,6 +109,7 @@ void GLWidget::InitGL()
/// </summary>
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
}
/// <summary>
@ -210,13 +277,82 @@ GLuint GLWidget::OutputTexID() { return m_OutputTexID; }
/// </summary>
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<T>::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<T>::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<T>::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.
}
/// <summary>
/// Wrapper around drawing a simple primitive, like a point or line, using a GLSL program.
/// </summary>
/// <param name="col">The color to draw with</param>
/// <param name="vertices">The vertices to use</param>
/// <param name="drawType">The type of primitive to draw, such as GL_POINT or GL_LINES</param>
void GLWidget::DrawPointOrLine(const QVector4D& col, const std::vector<float>& vertices, int drawType)
{
DrawPointOrLine(col, vertices.data(), vertices.size() / 2, drawType);
}
/// <summary>
/// Wrapper around drawing a simple primitive, like a point or line, using a GLSL program.
/// </summary>
/// <param name="col">The color to draw with</param>
/// <param name="vertices">The vertices to use</param>
/// <param name="size">The number of verticies. This is usually the size of vertices / 2.</param>
/// <param name="drawType">The type of primitive to draw, such as GL_POINT or GL_LINES</param>
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
}
/// <summary>
/// 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<T>::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
}
/// <summary>
@ -909,11 +1183,12 @@ void GLEmberController<T>::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<T> 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<T>::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<float, glm::defaultp> 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
}
/// <summary>
@ -963,6 +1292,7 @@ void GLEmberController<T>::DrawAffine(Xform<T>* xform, bool pre, bool selected)
auto size = ember->m_Palette.m_Entries.size();
auto color = ember->m_Palette.m_Entries[Clamp<T>(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<T>::DrawAffine(Xform<T>* 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<T>::DrawAffine(Xform<T>* 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<float, glm::defaultp> 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
}
/// <summary>
@ -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
}
/// <summary>

View File

@ -26,7 +26,12 @@ template<typename T> class FractoriumEmberController;
/// the main window and several of its members.
/// This class uses a controller-based design similar to the main window.
/// </summary>
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<float>& 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<float> m_Verts;
std::array<GLfloat, 10> 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;
};