From af64f953d4f01a7c7bd3415ff5edfff8d4f7c48d Mon Sep 17 00:00:00 2001 From: Stefan Suhren Date: Tue, 6 Oct 2015 12:52:40 +0200 Subject: Initial commit --- src/glitem.cpp | 408 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 src/glitem.cpp (limited to 'src/glitem.cpp') diff --git a/src/glitem.cpp b/src/glitem.cpp new file mode 100644 index 0000000..6e3984c --- /dev/null +++ b/src/glitem.cpp @@ -0,0 +1,408 @@ +#include "glitem.h" +#include "glesrenderer.h" +#include "gldefines.h" +#include "glcolorrgba.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef Q_OS_ANDROID +#ifndef GLES + #define GLES //Android uses GLES 2.0 +#endif +#endif + + +GLItem::GLItem(QQuickItem *parent, + const QString &vertexShaderFilename, + const QString &fragmentShaderFilename) : + QQuickItem(parent) +{ + m_fragmentShaderFilename = fragmentShaderFilename; + m_vertexShaderFilename = vertexShaderFilename; + setFlag(ItemHasContents); + m_geometryIsValid = false; + m_colorArrayEnabled = false; + m_texturesEnabled = false; + m_lightingEnabled = true; + m_activatePaintBeforeQml = false; + m_activatePaintAfterQml = true; + + m_lightDirection = v_XYZ; + m_backgroundColor = GLColorRgba::clBlue; + + m_eye = 1.5 * v_XYZ; + m_center = v_Zero; + m_up = v_Y; + //pespective + m_fovy = 45.0; + m_aspect = 1.0; + m_near = 1.0; + m_far = 100.0; + m_orthoMode = false; + + //The windowChanged signal is emitted by QQuickItem when it is added to the scenegraph. + //This is the first time when a valid window exists. + connect(this, SIGNAL(windowChanged(QQuickWindow*)), + this, SLOT(handleWindowChanged(QQuickWindow*))); + m_geometryIsValid = false; //invalidate geometry, we may need to set it up for the new window + m_timer = new QTimer(this); + m_timer->setInterval(20); + connect(m_timer, SIGNAL(timeout()), + this, SLOT(onTimerTimeout()), Qt::DirectConnection); + m_timer->start(50); + m_guiThreadRotation = 0.0; + m_renderThreadRotation = 0.0; + m_renderer = NULL; + m_firstAxesPoint = 0; + m_lastAxesPoint = 0; + m_viewportX = 0; + m_viewportY = 0; + setFlags(flags() | QQuickItem::ItemHasContents); +} + +GLItem::~GLItem() +{ + deleteRenderer(); +} + +/** + * @brief GlItem::updatePaintNode + * @param node Returns the root of the subtree to be rendered ON TOP of scene rendered + * in paint(). + * @return + */ + +QSGNode * GLItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *updatePaintNodeData) +{ + //qDebug() << "GlItem::updatePaintNode called"; + return QQuickItem::updatePaintNode(node, updatePaintNodeData); + + //remove the above line and uncomment the rest of this function to draw a blue rectangle + //Example code for a blue rectangle + /* QSGSimpleRectNode *rect = static_cast(node); + if (!rect) { + rect = new QSGSimpleRectNode(); + } + double w = 100; + if(window()) + w = window()->width(); + rect->setRect(0, 0, w, 100); + rect->setColor(Qt::blue); + return rect; + */ +} + +bool GLItem::movementActivated() +{ + return (m_timer && m_timer->isActive()); +} + + +void GLItem::paintBefore() +{ + // qDebug() << "GlItem::paintBefore() called"; + if(!m_renderer) + initializeRenderer(); + if(!m_geometryIsValid) + setupGeometry(); + if(!isVisible()) + return; + setupView(true, true); + m_renderer->bind(); + paintUnderQmlScene(); + m_renderer->release(); + window()->resetOpenGLState(); +} + +void GLItem::paintAfter() +{ + // qDebug() << "GlItem::paintBefore() called"; + + if(!m_renderer) + initializeRenderer(); + if(!m_geometryIsValid) + setupGeometry(); + if(!isVisible()) + return; + setupView(false, true); // enables scissor test + m_renderer->bind(); + paintOnTopOfQmlScene(); + m_renderer->release(); + glDisable(GL_SCISSOR_TEST); + window()->resetOpenGLState(); +} + +void GLItem::initializeRenderer() +{ + qDebug() <<"GlItem::initializeRenderer called."; + if(!m_renderer) + m_renderer = new GLESRenderer(NULL, m_vertexShaderFilename, m_fragmentShaderFilename); + +} + +void GLItem::deleteRenderer() +{ + qDebug() <<"GlItem::deleteRenderer() called."; + if(m_renderer) + { + delete m_renderer; + m_renderer = NULL; + } +} + +void GLItem::synchronizeThreads() +{ +// qDebug() << "GLItem::synchronizeThreads"; + m_renderThreadRotation = m_guiThreadRotation; +} + +void GLItem::timeOut() +{ + m_guiThreadRotation += 2.0; +} + +void GLItem::toggleMove() +{ + qDebug() << "GlItem::move() called"; + if(m_timer->isActive()) + m_timer->stop(); + else m_timer->start(); + emit movementActivatedChanged(); +} + +void GLItem::mousePressed(int x, int y) +{ + qDebug() << "GlItem::mousePressed at x:" << x << " y: " << y; +} + +void GLItem::mousePositionChanged(int x, int y) +{ + qDebug() << "GlItem::mouse position changed to x:" << x << " y: " << y; +} + +void GLItem::mouseReleased(int x, int y) +{ + qDebug() << "GlItem::mouse released at x:" << x << " y: " << y; +} + +void GLItem::setViewportX(int arg) +{ + if (m_viewportX == arg) + return; + + m_viewportX = arg; + emit viewportXChanged(arg); +} + +void GLItem::setViewportY(int arg) +{ + if (m_viewportY == arg) + return; + + m_viewportY = arg; + emit viewportYChanged(arg); +} + +void GLItem::setupView(bool clearColor, bool clearDepth) +{ + if(!m_renderer) + return; + + qreal ratio = window()->devicePixelRatio(); + int vx = int(ratio * m_viewportX); + int vy = int(ratio * m_viewportY); // y from bottom upwards! + int vw = int(ratio * width()); + int vh = int(ratio * height()); + glViewport(vx, vy, vw, vh); + //qDebug() << "GLItem::setupView viewport x: " << vx << " y: " << vy << " w: " << vw << " h: " << vh; + m_renderer->setViewport(vx, vy, vw, vh); + glEnable(GL_SCISSOR_TEST); + glScissor(vx,vy,vw,vh); + + m_aspect = (double)vw / (double)vh; + if(! m_orthoMode ){ + m_renderer->setPerspective(m_fovy, + m_aspect, + m_near, + m_far); + } + else m_renderer->setOrtho(-2.0, 2.0, -2.0, 2.0, 0.1, 100.0); // for debugging + m_renderer->setLookAt(m_eye, //eye + m_center, //center + m_up);//up + //setup light before turning + m_renderer->setLightDirection(m_lightDirection); + m_renderer->setLightingEnabled(true); + //now turn + m_renderer->addTransformation(m_cameraTransform); + + m_renderer->rotate(m_renderThreadRotation, QVector3D(0.0,0.0,1.0)); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(true); + + //Clear buffers as required +#ifndef GLES + glClearDepth(1.0); +#endif + glClearColor(m_backgroundColor.red(), m_backgroundColor.green(), + m_backgroundColor.blue(), m_backgroundColor.alpha()); + GLuint clearMode = 0; + if(clearColor) + clearMode |= GL_COLOR_BUFFER_BIT; + if(clearDepth) + clearMode |= GL_DEPTH_BUFFER_BIT; + glClear(clearMode); + + + glEnable(GL_BLEND); + glBlendFunc(1.0, 0.0); + // glPolygonMode(GL_FRONT, GL_FILL); + // glPolygonMode(GL_BACK, GL_LINES); +} + +/** + * @brief GlItem::handleWindowChanged + * + * Connect to the window's signals. This can not be done in the constructor, because at that time + * there is no valid window yet. + * @param win The window in which this QQuickItem will be painted. + */ +void GLItem::handleWindowChanged(QQuickWindow *win) +{ + qDebug() << "GlItem::handleWindowChanged() called."; + if (win) { + // Connect the beforeRendering signal to our paint function. + // Since this call is executed on the rendering thread it must be + // a Qt::DirectConnection + if(m_activatePaintBeforeQml) + connect(win, SIGNAL(beforeRendering()), + this, SLOT(paintBefore()), Qt::DirectConnection); + if(m_activatePaintAfterQml) + connect(win, SIGNAL(afterRendering()), + this, SLOT(paintAfter()), Qt::DirectConnection); + connect(win, SIGNAL(beforeSynchronizing()), + this, SLOT(slotSynchronizeThreads()), Qt::DirectConnection); + if(win->openglContext()) + connect(win->openglContext(), SIGNAL(aboutToBeDestroyed()), //cleanup context before destroying window + this, SLOT(deleteRenderer()), Qt::DirectConnection); + // If we allow QML to do the clearing, they would clear what we paint + // and nothing would show. + win->setClearBeforeRendering(false); + } +} + +void GLItem::onTimerTimeout() +{ + //qDebug() << "GlItem::onTimerTimeout() called"; + timeOut(); + if (window()) + window()->update(); +} + +void GLItem::slotSynchronizeThreads() +{ + synchronizeThreads(); +} + +void GLItem::setupGeometry() +{ + m_geometryIsValid = true; +} + + +void GLItem::paintUnderQmlScene() +{ + qDebug() << "GlItem::paintUnderQmlScene() was called. Overwrite this function to paint your scene!"; +} + +void GLItem::paintOnTopOfQmlScene() +{ + qDebug() << "GlItem::paintOnTopOfQmlScene() was called. Overwrite this function to paint your scene!"; +} + +void GLItem::drawAxes(double length) +{ + if(m_lastAxesPoint == 0) + createAxes(length); + GLfloat lineWidth[4]; //4 floats, just for safety + glGetFloatv(GL_LINE_WIDTH, lineWidth); + glLineWidth(3.0); + m_renderer->setColorArrayEnabled(true); + + m_renderer->setLightingEnabled(false); + int stride = sizeof(GLPoint); + m_renderer->activateAttributeArray(GLESRenderer::VERTEX_LOCATION, + m_points[0].vertexPointer(), stride); + m_renderer->activateAttributeArray(GLESRenderer::COLOR_LOCATION, + m_points[0].colorPointer(), stride); + glDrawArrays(GL_LINES, m_firstAxesPoint, m_lastAxesPoint - m_firstAxesPoint); //Coordinate Axes + m_renderer->disableAttributeArrays(); + //restore old settings + m_renderer->setColorArrayEnabled(false); + m_renderer->setLightingEnabled(true); + glLineWidth(lineWidth[0]); +} + +void GLItem::createAxis(double length, const QVector3D & origin, const QVector3D & axis, + const QVector3D & normal, const QVector3D & texCoord, + const GLColorRgba& color) +{ + int ticks = floor(length); + double tickLength = 0.1; + double tickLongLength = tickLength * 2; + m_points.append(GLPoint(origin, normal, texCoord,color)); + m_points.append(GLPoint(axis * length, normal, texCoord,color)); + for(int tick = 1; tick <= ticks; tick++) + { + if(tick % 5 == 0) + { + m_points.append(GLPoint(origin + axis * tick, normal, texCoord, color)); + m_points.append(GLPoint(origin + axis * tick + normal * tickLongLength, normal, texCoord, color)); + } + else + { + m_points.append(GLPoint(origin + axis * tick, normal, texCoord, color)); + m_points.append(GLPoint(origin + axis * tick + normal * tickLength, normal, texCoord, color)); + } + } +} + +void GLItem::createAxes(double length) +{ + + m_firstAxesPoint = m_points.size(); + + //X-axis + QVector3D origin = v_Zero; + QVector3D axis = v_X; + QVector3D normal = v_Y; + QVector3D texCoord = v_Zero; + GLColorRgba color = cl_Red; + + createAxis(length, origin, axis, normal, texCoord, color); + //Y-Axis + axis = v_Y; + normal = v_Z; + color= cl_Green; + createAxis(length, origin, axis, normal, texCoord, color); + + //Z-Axis + axis = v_Z; + normal = v_X; + color= cl_Blue; + createAxis(length, origin, axis, normal, texCoord, color); + + m_lastAxesPoint = m_points.size(); +} + -- cgit v1.2.3-70-g09d2