/*************************************************************************** * 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 #include #include /**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 *pointContainer, QVector * indexContainer) { if(pointContainer == NULL) { m_points = new QVector(); m_ownPointsContainer = true; } else m_points = pointContainer; if(indexContainer == NULL) { m_indices = new QVector(); 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; }