Skip to content
59 changes: 53 additions & 6 deletions avogadro/qtopengl/glwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@

#include <avogadro/rendering/camera.h>

#include <QAction>
#include <QDebug>
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QAction>
#include <QtWidgets/QApplication>
#include <QtGui/QWindow>
#include <QtWidgets/QApplication>

namespace Avogadro::QtOpenGL {

GLWidget::GLWidget(QWidget* p)
: QOpenGLWidget(p), m_activeTool(nullptr), m_defaultTool(nullptr),
m_renderTimer(nullptr)
m_renderTimer(nullptr), m_logger(nullptr)
{
setFocusPolicy(Qt::ClickFocus);
connect(&m_scenePlugins,
Expand Down Expand Up @@ -169,7 +170,9 @@ void GLWidget::setDefaultTool(const QString& name)
{
foreach (QtGui::ToolPlugin* tool, m_tools) {
QAction* toolAction = tool->activateAction();
if (tool->name() == name || (toolAction && toolAction->text() == name)) {

if (tool->objectName() == name || tool->name() == name ||
(toolAction && toolAction->text() == name)) {
setDefaultTool(tool);
return;
}
Expand Down Expand Up @@ -215,11 +218,46 @@ void GLWidget::updateTimeout()
update();
}

void GLWidget::logMessage(const QOpenGLDebugMessage& debugMessage)
{
qDebug() << " OpenGL: " << debugMessage;
}

void GLWidget::initializeGL()
{
m_renderer.initialize();
if (!m_renderer.isValid())

if (!m_renderer.isValid()) {
qWarning("Failed to initialize the renderer.");
qWarning() << m_renderer.error().c_str();
emit rendererInvalid();
} else {
qDebug() << " Renderer initialized.";
}

// check the surface format
QSurfaceFormat format = this->format();
qDebug() << " Surface format: " << format.majorVersion() << "."
<< format.minorVersion();
// compatibility or core profile?
if (format.profile() == QSurfaceFormat::CompatibilityProfile)
qDebug() << " Compatibility profile";
else if (format.profile() == QSurfaceFormat::CoreProfile)
qDebug() << " Core profile";

// multisampling?
if (format.samples() > 0)
qDebug() << " Multisampling: " << format.samples();

// initialize the logger
m_logger = new QOpenGLDebugLogger(this);
if (m_logger->initialize()) {
qDebug() << " OpenGL debug logger initialized.";

connect(m_logger, &QOpenGLDebugLogger::messageLogged, this,
&GLWidget::logMessage);
m_logger->startLogging();
}
}

void GLWidget::resizeGL(int width_, int height_)
Expand All @@ -232,6 +270,15 @@ void GLWidget::resizeGL(int width_, int height_)
void GLWidget::paintGL()
{
m_renderer.render();

// make sure the context is still good
if (m_renderer.isValid()) {
auto* context = QOpenGLContext::currentContext();
if (context) {
qDebug() << " OGL Context" << context->isValid() << " fbo "
<< context->defaultFramebufferObject();
}
}
}

void GLWidget::mouseDoubleClickEvent(QMouseEvent* e)
Expand Down Expand Up @@ -332,4 +379,4 @@ void GLWidget::keyReleaseEvent(QKeyEvent* e)
QOpenGLWidget::keyReleaseEvent(e);
}

} // namespace Avogadro
} // namespace Avogadro::QtOpenGL
16 changes: 12 additions & 4 deletions avogadro/qtopengl/glwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
#include <avogadro/qtgui/toolplugin.h>
#include <avogadro/rendering/glrenderer.h>

#include <QPointer>
#include <QOpenGLWidget>
#include <QPointer>

#include <QOpenGLDebugLogger>

class QTimer;

Expand Down Expand Up @@ -111,6 +113,11 @@ public slots:
*/
void updateScene();

/**
* OpenGL Error Message logged
*/
void logMessage(const QOpenGLDebugMessage& debugMessage);

/**
* Clear the contents of the scene.
*/
Expand Down Expand Up @@ -194,9 +201,10 @@ protected slots:
QtGui::ScenePluginModel m_scenePlugins;

QTimer* m_renderTimer;
QOpenGLDebugLogger* m_logger;
};

} // End QtOpenGL namespace
} // End Avogadro namespace
} // namespace QtOpenGL
} // namespace Avogadro

#endif // AVOGADRO_QTOPENGL_GLWIDGET_H
#endif // AVOGADRO_QTOPENGL_GLWIDGET_H
2 changes: 2 additions & 0 deletions avogadro/rendering/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ set(shader_files
"mesh_fs.glsl"
"mesh_opaque_fs.glsl"
"mesh_vs.glsl"
"mesh_tcs.glsl"
"mesh_tev.glsl"
"solid_vs.glsl"
"solid_first_fs.glsl"
"spheres_fs.glsl"
Expand Down
20 changes: 13 additions & 7 deletions avogadro/rendering/mesh_fs.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
varying vec3 fnormal;
#version 400
precision highp float;

in vec3 fnormal;
in vec4 outColor;

out vec4 colorOut;

void main()
{
Expand All @@ -9,9 +15,9 @@ void main()
float df = max(0.0, dot(N, L));
float sf = max(0.0, dot(N, H));
sf = pow(sf, 20.0);
vec4 ambient = gl_Color / 3.0;
vec4 diffuse = gl_Color;
vec4 specular = gl_Color * 3.0;
gl_FragColor = ambient + df * diffuse + sf * specular;
gl_FragColor.a = gl_Color.a;
}
vec4 ambient = outColor / 3.0;
vec4 diffuse = outColor;
vec4 specular = outColor * 3.0;
colorOut = ambient + df * diffuse + sf * specular;
colorOut.a = outColor.a;
}
20 changes: 13 additions & 7 deletions avogadro/rendering/mesh_opaque_fs.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
varying vec3 fnormal;
#version 430
// precision highp float;

in vec3 fnormal;
in vec4 outColor;

out vec4 colorOut;

void main()
{
Expand All @@ -9,9 +15,9 @@ void main()
float df = max(0.0, dot(N, -L));
float sf = max(0.0, dot(N, -H));
sf = pow(sf, 32.0);
vec4 ambient = gl_Color / 2.2;
vec4 diffuse = gl_Color * 1.1;
vec4 specular = gl_Color * 5.0;
gl_FragColor = ambient + df * diffuse + sf * specular;
gl_FragColor.a = gl_Color.a;
}
vec4 ambient = outColor / 2.2;
vec4 diffuse = outColor * 1.1;
vec4 specular = outColor * 5.0;
colorOut = ambient + df * diffuse + sf * specular;
colorOut.a = outColor.a;
}
100 changes: 100 additions & 0 deletions avogadro/rendering/mesh_tcs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#version 400
precision highp float; // precision qualifier

// outputing a single CP
layout(vertices = 1) out;

in vec3 WorldPos_CS_in[];
in vec2 TexCoord_CS_in[];
in vec3 fnormal[];

struct OutputPatch {
vec3 WorldPos_B030;
vec3 WorldPos_B021;
vec3 WorldPos_B012;
vec3 WorldPos_B003;
vec3 WorldPos_B102;
vec3 WorldPos_B201;
vec3 WorldPos_B300;
vec3 WorldPos_B210;
vec3 WorldPos_B120;
vec3 WorldPos_B111;

vec3 Normal[3];
vec2 TexCoord[3];
};

const float gTessellationLevel = 4.0; // Constant declaration is fine

// encapsulated all the data of the output patch in the OutputPatch
// struct above and declared an output variable called oPatch of that type

out patch OutputPatch oPatch;


// This function is used by CalcPositions() to project a midpoint on
// the plane defined by the nearest vertex and its normal.
vec3 ProjectToPlane(vec3 Point, vec3 PlanePoint, vec3 PlaneNormal) {
vec3 v = Point - PlanePoint;
float Len = dot(v, PlaneNormal);
vec3 d = Len * PlaneNormal;
return (Point - d);
}

void CalcPositions() {
// The original vertices stay the same
oPatch.WorldPos_B030 = WorldPos_CS_in[0];
oPatch.WorldPos_B003 = WorldPos_CS_in[1];
oPatch.WorldPos_B300 = WorldPos_CS_in[2];

// Edges are named according to the opposing vertex
vec3 EdgeB300 = oPatch.WorldPos_B003 - oPatch.WorldPos_B030;
vec3 EdgeB030 = oPatch.WorldPos_B300 - oPatch.WorldPos_B003;
vec3 EdgeB003 = oPatch.WorldPos_B030 - oPatch.WorldPos_B300;

// Generate two midpoints on each edge
oPatch.WorldPos_B021 = oPatch.WorldPos_B030 + EdgeB300 / 3.0;
oPatch.WorldPos_B012 = oPatch.WorldPos_B030 + EdgeB300 * 2.0 / 3.0;
oPatch.WorldPos_B102 = oPatch.WorldPos_B003 + EdgeB030 / 3.0;
oPatch.WorldPos_B201 = oPatch.WorldPos_B003 + EdgeB030 * 2.0 / 3.0;
oPatch.WorldPos_B210 = oPatch.WorldPos_B300 + EdgeB003 / 3.0;
oPatch.WorldPos_B120 = oPatch.WorldPos_B300 + EdgeB003 * 2.0 / 3.0;

// Project each midpoint on the plane defined by the nearest vertex and its normal
oPatch.WorldPos_B021 = ProjectToPlane(oPatch.WorldPos_B021, oPatch.WorldPos_B030, oPatch.Normal[0]);
oPatch.WorldPos_B012 = ProjectToPlane(oPatch.WorldPos_B012, oPatch.WorldPos_B003, oPatch.Normal[1]);
oPatch.WorldPos_B102 = ProjectToPlane(oPatch.WorldPos_B102, oPatch.WorldPos_B003, oPatch.Normal[1]);
oPatch.WorldPos_B201 = ProjectToPlane(oPatch.WorldPos_B201, oPatch.WorldPos_B300, oPatch.Normal[2]);
oPatch.WorldPos_B210 = ProjectToPlane(oPatch.WorldPos_B210, oPatch.WorldPos_B300, oPatch.Normal[2]);
oPatch.WorldPos_B120 = ProjectToPlane(oPatch.WorldPos_B120, oPatch.WorldPos_B030, oPatch.Normal[0]);

// Handle the center
vec3 Center = (oPatch.WorldPos_B003 + oPatch.WorldPos_B030 + oPatch.WorldPos_B300) / 3.0;
oPatch.WorldPos_B111 = (oPatch.WorldPos_B021 + oPatch.WorldPos_B012 + oPatch.WorldPos_B102 +
oPatch.WorldPos_B201 + oPatch.WorldPos_B210 + oPatch.WorldPos_B120) / 6.0;
oPatch.WorldPos_B111 += (oPatch.WorldPos_B111 - Center) / 2.0;
}

void main(void) {

// The three normals and texture coordinates are copied
// as-is from the input into the output patch.

for (int i = 0 ; i < 3 ; i++) {
oPatch.Normal[i] = fnormal[i];
oPatch.TexCoord[i] = TexCoord_CS_in[i];
}

// The 10 CPs that we are going to generate contain only a position value.
// This is done in a dedicated function called CalcPositions()

CalcPositions();

// Calculate the tessellation levels
gl_TessLevelOuter[0] = gTessellationLevel;
gl_TessLevelOuter[1] = gTessellationLevel;
gl_TessLevelOuter[2] = gTessellationLevel;
gl_TessLevelOuter[3] = gTessellationLevel;
gl_TessLevelInner[0] = gTessellationLevel;
gl_TessLevelInner[1] = gTessellationLevel;
}
59 changes: 59 additions & 0 deletions avogadro/rendering/mesh_tev.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#version 400
precision highp float; // precision qualifier
layout(triangles, equal_spacing, ccw) in; // layout qualifier

uniform mat4 projection;
uniform mat4 modelView;

struct OutputPatch {
vec3 WorldPos_B030;
vec3 WorldPos_B021;
vec3 WorldPos_B012;
vec3 WorldPos_B003;
vec3 WorldPos_B102;
vec3 WorldPos_B201;
vec3 WorldPos_B300;
vec3 WorldPos_B210;
vec3 WorldPos_B120;
vec3 WorldPos_B111;

vec3 Normal[3];
vec2 TexCoord[3];
};

in patch OutputPatch oPatch; // input patch qualifier
out vec3 WorldPos_FS_in;
out vec2 TexCoord_FS_in;
out vec3 Normal_FS_in;

vec2 interpolate2D(vec2 v0, vec2 v1, vec2 v2) {
return vec2(gl_TessCoord.x) * v0 + vec2(gl_TessCoord.y) * v1 + vec2(gl_TessCoord.z) * v2;
}

vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2) {
return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2;
}

void main() {
// Interpolate the attributes of the output vertex using the barycentric coordinates
TexCoord_FS_in = interpolate2D(oPatch.TexCoord[0], oPatch.TexCoord[1], oPatch.TexCoord[2]);
Normal_FS_in = interpolate3D(oPatch.Normal[0], oPatch.Normal[1], oPatch.Normal[2]);

// bezier curve formula.

float u = gl_TessCoord.x;
float v = gl_TessCoord.y;
float w = gl_TessCoord.z;
float uPow3 = pow(u, 3);
float vPow3 = pow(v, 3);
float wPow3 = pow(w, 3);
float uPow2 = pow(u, 2);
float vPow2 = pow(v, 2);
float wPow2 = pow(w, 2);
WorldPos_FS_in = oPatch.WorldPos_B300 * wPow3 + oPatch.WorldPos_B030 * uPow3 + oPatch.WorldPos_B003 * vPow3 +
oPatch.WorldPos_B210 * 3.0 * wPow2 * u + oPatch.WorldPos_B120 * 3.0 * w * uPow2 + oPatch.WorldPos_B201 * 3.0 * wPow2 * v +
oPatch.WorldPos_B021 * 3.0 * uPow2 * v + oPatch.WorldPos_B102 * 3.0 * w * vPow2 + oPatch.WorldPos_B012 * 3.0 * u * vPow2 +
oPatch.WorldPos_B111 * 6.0 * w * u * v;

gl_Position = modelView * projection * vec4(WorldPos_FS_in, 1.0);
}
Loading