diff options
| -rw-r--r-- | MM_2015_Base_Project.pro | 8 | ||||
| -rw-r--r-- | src/glbody.cpp | 272 | ||||
| -rw-r--r-- | src/glbody.h | 225 |
3 files changed, 502 insertions, 3 deletions
diff --git a/MM_2015_Base_Project.pro b/MM_2015_Base_Project.pro index 5caf8e2..051b639 100644 --- a/MM_2015_Base_Project.pro +++ b/MM_2015_Base_Project.pro @@ -1,6 +1,6 @@ TEMPLATE = app -QT += qml quick widgets +QT += qml quick widgets opengl SOURCES += \ src/main.cpp \ @@ -9,7 +9,8 @@ SOURCES += \ src/glitem.cpp \ src/glpoint.cpp \ src/shaderdebugger.cpp \ - src/mmscene.cpp + src/mmscene.cpp \ + src/glbody.cpp HEADERS += \ src/glcolorrgba.h \ @@ -18,7 +19,8 @@ HEADERS += \ src/glitem.h \ src/glpoint.h \ src/shaderdebugger.h \ - src/mmscene.h + src/mmscene.h \ + src/glbody.h RESOURCES += qml.qrc \ shaders.qrc diff --git a/src/glbody.cpp b/src/glbody.cpp new file mode 100644 index 0000000..b1be10f --- /dev/null +++ b/src/glbody.cpp @@ -0,0 +1,272 @@ +/*************************************************************************** + * Copyright (C) 2008, 2012 by Walter Roth * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "glbody.h" + +#include <QImage> +#include <QtOpenGL/QGLWidget> +#include <QFile> + +/**Constructor does NOT create the surface. +*/ +GLBody::GLBody(float radius, const GLColorRgba &color, const QString textureFile) +{ + m_surfaceIsValid = false; + this->m_textureFile = textureFile; //DO NOT call setTextureFile here! It needs a current context! + m_texture = 0; + this->m_color = color; + m_specularColor = cl_White; + m_shininess = 50; + this->m_radius = radius; + m_drawingMode = GL_TRIANGLES; + m_selected = false; + m_points = NULL; + m_ownPointsContainer = false; + m_indices = NULL; + m_ownIndexContainer = false; + m_firstPoint = 0; + m_nextPoint = 0; + m_firstIndex = 0; + m_nextIndex = 0; +} + +/** Destructor + */ +GLBody::~GLBody() +{ + if(m_texture != 0){//delete an existing texture + glDeleteTextures(1, &m_texture); + m_texture = 0; + } + if(m_ownPointsContainer) + delete m_points; + if(m_ownIndexContainer) + delete m_indices; +} + +/** Creates the surface. Should be called, when a GL engine is already running. + * Is called automatically by draw, if required. + */ +void GLBody::makeSurface(QVector<GLPoint> *pointContainer, QVector<GLshort> * indexContainer) +{ + if(pointContainer == NULL) + { + m_points = new QVector<GLPoint>(); + m_ownPointsContainer = true; + } + else m_points = pointContainer; + if(indexContainer == NULL) + { + m_indices = new QVector<GLshort>(); + m_ownIndexContainer = true; + } + else m_indices = indexContainer; + setTexture(m_textureFile); + m_surfaceIsValid = true; +} + +void GLBody::calculateDrawMatrix() +{ + m_drawMatrix = m_transformationMatrix; +} + +/** Draws the surface and calls makeSurface if required. + * Needs an active (made current) GL-Context. + */ +void GLBody::draw(GLESRenderer * renderer){ + if(!m_surfaceIsValid) + makeSurface(NULL, NULL); + if(!m_points || m_points->size() == 0) //check for existing points + { + qDebug() << "GLESBody::draw ERROR: No points!"; + return; + } + int stride = sizeof(GLPoint); + bool oldTextureEnabled = false; + + //set colors + renderer->setAmbientAndDiffuseColor(m_color); + + //enable required arrays + renderer->activateAttributeArray(GLESRenderer::VERTEX_LOCATION, + (*m_points)[0].vertexPointer(), stride); + if (renderer->isLightingEnabled()) + renderer->activateAttributeArray(GLESRenderer::NORMAL_LOCATION, + (*m_points)[0].normalPointer(), stride); + if(m_texture != 0){ + glActiveTexture(GL_TEXTURE0); //use texture unit 0 + glBindTexture(GL_TEXTURE_2D, m_texture); + oldTextureEnabled = renderer->isTextureEnabled(); + renderer->setTextureEnabled(true); + } + else renderer->setTextureEnabled(false); + renderer->activateAttributeArray(GLESRenderer::TEXCOORD_LOCATION, + (*m_points)[0].texCoordPointer(), stride); + renderer->activateAttributeArray(GLESRenderer::COLOR_LOCATION, + (*m_points)[0].colorPointer(), stride); + +// for(int i = 0; i < indices.count(); i++) +// points[indices[i]].debugOutput("Point" +QString::number(i) + ":" + QString::number(indices[i]) + " "); + + calculateDrawMatrix(); + renderer->pushMvMatrix(); + renderer->addTransformation(m_drawMatrix); + if(m_firstIndex >= 0 && m_nextIndex > 0) + glDrawElements(m_drawingMode, m_nextIndex -m_firstIndex, + GL_UNSIGNED_SHORT, &m_indices->data()[m_firstIndex]); + else + glDrawArrays(m_drawingMode, m_firstPoint, m_nextPoint - m_firstPoint); + + if(isSelected()) + { + bool lightingOn = renderer->isLightingEnabled(); + if(lightingOn) + renderer->setLightingEnabled(false); + GLColorRgba pointColor(m_color.inverted()); + renderer->setAmbientAndDiffuseColor(pointColor); +#ifdef GLES + glDrawArrays(GL_LINES, 0, m_points->size()); +#else + int oldPointSize = renderer->getPointSize(); + renderer->setPointSize(5); + glDrawArrays(GL_POINTS, 0, m_points->size()); + renderer->setPointSize(oldPointSize); +#endif + if(lightingOn) + renderer->setLightingEnabled(true); + } + //disable arrays + renderer->disableAttributeArrays(); + if(m_texture != 0) + renderer->setTextureEnabled(oldTextureEnabled); + renderer->popMvMatrix(); +} + +/** Set texture from file. Returns true on success + */ +bool GLBody::setTexture(const QString & textureFile){ + if(textureFile == "") + return false; + + QImage image; + if(m_texture != 0){//delete an existing texture + glDeleteTextures(1, &m_texture); + m_texture = 0; + } + + qDebug("%s", QString("Loading Texture:" + textureFile).toLatin1().data()); + if (image.load(textureFile)){ + //we have got a valid image, give it to GL + if (image.format() != QImage::Format_ARGB32) //make shure, that we have 32bit colors + image = image.convertToFormat(QImage::Format_ARGB32); + image = QGLWidget::convertToGLFormat(image); + glGenTextures(1, &m_texture); // get a number (name) for the new texture and create a new texture object + if(m_texture == 0) //GL does not work properly + { + qDebug("Could not create texture object. GL-engine not yet active?"); + return false; + } + glBindTexture(GL_TEXTURE_2D, m_texture); // Bind texture object to OpenGL. + //All following calls work on the bound texture object. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_NEAREST); //use values of nearest pixel for magnification. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST); // use nearest pixel minimization. + // Replace with other values if aliasing occurs. See doc for GL_TEXTURE_MAG_FILTER + + //The next call copies the pixel data from the QImage, which is no longer needed afterwards. + glTexImage2D(GL_TEXTURE_2D, + 0, // use only one resolution + GL_RGBA, //internal format to use for the texture + image.width(), + image.height(), + 0, //width of the texture border, may be 0 or 1 + GL_RGBA, //format of the QImage + GL_UNSIGNED_BYTE, // QImage uses values from 0 to 255 for R,G,B,A + image.bits() //pointer to the first pixel in image + ); + glBindTexture(GL_TEXTURE_2D, 0); // finally remove texture from OpenGL machine + return true; + } + else{ //loading failed + qDebug("Texture loading failed"); + return false; + } +} + +/** Set texture file. + */ +bool GLBody::setTextureFile(const QString & textureFile){ + this->m_textureFile = textureFile; + if(m_texture != 0) //we have an activated texture already. Replace it. + return setTexture(textureFile); + else return true; //texture is not yet active, leave it as it is +} + +/** + * Moves the body by adding vMove to all vertices. + */ +void GLBody::move(QVector3D vMove) +{ + for(int i = m_firstPoint; i < m_nextPoint; i++) + (*m_points)[i].move(vMove); + m_center = m_center + vMove; +} + +/** + * Returns true, when line through p1 and p2 intersects body shpere + */ +bool GLBody::isHit(QVector3D p1, QVector3D p2) +{ + QVector3D lineVector = p2 - p1; + double area = QVector3D::crossProduct((m_center - p1), lineVector).length(); + double distance = area / lineVector.length(); + //qDebug("Radius: %f", radius); + return distance < m_radius; +} + +/* + * Returns true, if enclosing spheres touch or intersect + */ +bool GLBody::spheresAreColliding(const GLBody *other) +{ + bool result; + if(this == other) + result = false; + else + { + double distance = (m_center - other->m_center).length(); + result = (m_radius + other->m_radius) >= distance; + } + if(result) + return true; //hook for debugger + else return false; //hook for debugger +} + +/** + * Set new center and invalidate surface. + */ +void GLBody::setCenter(const QVector3D & newVal) +{ + m_center = newVal; + m_surfaceIsValid = false; +} + + diff --git a/src/glbody.h b/src/glbody.h new file mode 100644 index 0000000..1bbaa82 --- /dev/null +++ b/src/glbody.h @@ -0,0 +1,225 @@ +/*************************************************************************** + * Copyright (C) 2008, 2012 by Walter Roth * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef GLBODY_H +#define GLBODY_H + +#include <QVector> + +#include "glesrenderer.h" +#include "glpoint.h" +#include "gldefines.h" + +/** + * \brief A 3D body that uses a GLESRenderer for drawing and GLPoint objects for defining its surface. + * + * Overwrite makeSurface() in subclasses to create the GLPoints that form the surface. + * Set drawingMode to GL_LINE_STRIP or GL_LINES for debugging the surface. Default is GL_TRIANGLE_STRIP. + * Vertices and indices may be stored in external or internal containers. If GlBody::makeSurface is called + * with pointers to existing containers, these will be used. Otherwise GlBody::makeSurface will create new + * containers. Only in this case, the destructor will delete the containers. + * Overwrite draw() if you do need special drawing procedures. + */ +class GLBody{ +public: + /**Constructor does NOT create the surface. + */ + GLBody(float m_radius = 1.0, const GLColorRgba & m_color = GLColorRgba::clBlue, const QString m_textureFile = ""); + + /** Destructor will delete created containers. + */ + virtual ~GLBody(); + + /** Creates the surface. Should be called, when a GL engine is already running. + * To be overwritten by subclasses. GLESBody::createSurface should be called at the beginning + * of overriding functions. It will create the pointContainer, if none is supplied + * Is called automatically by draw, if required. + * MUST NOT be called without a working GL engine. + * + * @param pointContainer The container for the geometry data. If NULL, a new one is created. + * @param indexContainer The container for the index data. If NULL, a new one is created. + * Created containers will be deleted by destructor. + */ + virtual void makeSurface(QVector<GLPoint> * pointContainer, QVector<GLshort> * indexContainer); + + + /** + * @brief calculateDrawMatrix Virtual function to calculate the final matrix to be used for drawing. + * May be overwritten in subclasses. GLBody::calculateDrawMatrix simply copies m_transformationMatrix. + */ + virtual void calculateDrawMatrix(); + /** Draws the surface and calls makeSurface if required. + * Needs an active (made current) GL-Context. + */ + virtual void draw(GLESRenderer * renderer); + + /** + * Returns true, when line through p1 and p2 intersects body sphere + * To be overwritten by subclasses. + */ + virtual bool isHit(QVector3D p1, QVector3D p2); + + /** + * Returns true, if enclosing spheres touch or intersect + */ + virtual bool spheresAreColliding(const GLBody * other); + + /** Set texture from file. Returns true on success. Needs a current OpenGL context. + */ + bool setTexture(const QString & m_textureFile); + + /** Set texture file. Needs a current OpenGL context. + */ + bool setTextureFile(const QString & m_textureFile); + + /** + * Moves the body by adding vMove to all vertices. + */ + void move(QVector3D vMove); + /** + * Simple gettters + */ + bool isSelected(){return m_selected;} + const QVector3D & getCenter()const{return m_center;} + + /**Simple setters + */ + void setColor(const GLColorRgba & newVal){m_color = newVal;} + void setSpecularColor(const GLColorRgba & newVal){m_specularColor = newVal;} + void setShininess(int newVal){m_shininess = newVal;} + void setSelected(bool newVal){m_selected = newVal;} + void setDrawingMode(GLint newVal){m_drawingMode = newVal;} + void setTransformation(const QMatrix4x4 & transformation){m_transformationMatrix = transformation;} + + /** + * Set new center and invalidate surface. + */ + void setCenter(const QVector3D & newVal); + + /** + *Simple getters + */ + const GLColorRgba & getColor()const{return m_color;} + const QMatrix4x4 & getTransformation()const{return m_transformationMatrix;} + double getRadius()const{return m_radius;} + void setScale(double scale){m_scale = scale;} + +protected: + /** + * The center of the enclosing sphere + */ + QVector3D m_center; + + /** + * The radius of the enclosing sphere + */ + GLfloat m_radius; + + /** + * The mode to be passed to glDrawArrays or glDrawElements e.g. GL_TRIANGLES, GL_TRIANGLE_STRIP + */ + GLint m_drawingMode; + + /** The array of points defining the surface. + * This *may be* a container not owned by this body. + */ + QVector <GLPoint> * m_points; + + /** + * @brief ownPointsContainer Set this Flag, if points container was created by this body. + */ + bool m_ownPointsContainer; + + /** + * @brief firstPoint The firstPoint for this body + */ + int m_firstPoint; + + /** + * @brief lastPoint The next point for this body. ( last point +1) + */ + int m_nextPoint; + + /** The array with the indices. May be left empty. + */ + QVector <GLshort> * m_indices; + + /** + * @brief ownPointsContainer Set this Flag, if points container was created by this body. + */ + bool m_ownIndexContainer; + + /** + * @brief startIndex The first index for this body + */ + int m_firstIndex; + + /** + * @brief indexCount The next index for this body. (last index + 1) + */ + int m_nextIndex; + + /** The flag for a valid surface. + */ + bool m_surfaceIsValid; + + /** The texture to be used. + */ + GLuint m_texture; + + /** The tetxure file. + */ + QString m_textureFile; + + /** The diffuse and ambient color for the body. + */ + GLColorRgba m_color; + + /** + * The specular color + */ + GLColorRgba m_specularColor; + + /** + * Shininess for specular color + */ + int m_shininess; + + /** + * Flag for selected mode. + */ + bool m_selected; + /** + * This matrix holds the basic transformation for the body and + * should not be modified after first setting. + */ + QMatrix4x4 m_transformationMatrix; + + /** + * @brief m_drawMatrix + * This matrix is multiplied with the modelview matrix prior to + * rendering the body. + */ + QMatrix4x4 m_drawMatrix; + /** + * @brief m_scale + */ + double m_scale; //meters per logical unit +}; + +#endif |
