diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000..3932671 --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,23 @@ +//varying vec3 normal, lightDir; +uniform sampler2D tex; + +void main() +{ + vec4 color; + vec4 texel; + float alpha,r,g,b ; + + texel = texture2D(tex,gl_TexCoord[0].st); + alpha = texel.a; + + r = ((-(alpha-1.0)*(alpha-1.0)/0.1)+1.0); + g = (5.0*(-((alpha-0.5)*(alpha-0.5))/0.4)+1.0); + b = ((-(alpha * alpha)/0.15)+1.0); + + if (r<0) r=0 ; + if (g<0) g=0 ; + if (b<0) b=0 ; + + color = vec4(r,g,b,alpha); + gl_FragColor = color; +} diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000..9577eed --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,6 @@ + +void main() +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); +} diff --git a/shaders/shader3D.frag b/shaders/shader3D.frag new file mode 100644 index 0000000..e46d34c --- /dev/null +++ b/shaders/shader3D.frag @@ -0,0 +1,22 @@ +uniform sampler3D tex; + +void main() +{ + vec4 color; + vec4 texel; + float alpha,r,g,b ; + + texel = texture3D(tex,gl_TexCoord[0].xyz); + alpha = texel.a; + + r = ((-(alpha-1.0)*(alpha-1.0)/0.1)+1.0); + g = (5.0*(-((alpha-0.5)*(alpha-0.5))/0.4)+1.0); + b = ((-(alpha * alpha)/0.15)+1.0); + + if (r<0) r=0 ; + if (g<0) g=0 ; + if (b<0) b=0 ; + + color = vec4(r,g,b,alpha); + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/BBWindow.cpp b/src/BBWindow.cpp new file mode 100644 index 0000000..2003905 --- /dev/null +++ b/src/BBWindow.cpp @@ -0,0 +1,881 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 "BBWindow.h" + +BBWindow::BBWindow() + :QMainWindow(), mShowFps(false), mDensityWidget(NULL), numScene(1),isBCC(false) +{ + ui.setupUi(this); + + // Init QGL + QGLFormat format; + format.setDoubleBuffer(true); + format.setDepth(true); + format.setRgba(true); + format.setAlpha(true); + format.setStencil(true); + format.setStereo(false); + QGLFormat::setDefaultFormat(format); + + // Chargement viewer en fenètre Main + mViewer = new Viewer(this); + mViewer->setFocus(); + setCentralWidget(mViewer); + // Attachement d'une scène au viewer + mScene = new Scene(); + mScene2 = new Scene(); + + mViewer->attachScene(mScene, mScene2); + + // /!\ Ne Pas Modifier la fenètre ICI ! Utiliser QtDesigner et le .ui ! + // Action de la fenêtre Main + connect(mViewer, SIGNAL(glInitialized()), this, SLOT(createScene())); + + // Fichier + connect(ui.actionCharger_un_Maillage, SIGNAL(triggered()), this, SLOT(loadObjectDialog())); + connect(ui.actionChargerTexture,SIGNAL(triggered()), this, SLOT(loadTextureDialog())); + connect(ui.actionSauvegarder,SIGNAL(triggered()), this, SLOT(SaveAs())); + connect(ui.actionQuit, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); + + // Affichage + connect(ui.actionGauche,SIGNAL(triggered()), this, SLOT(selectViewPortLeft())); + connect(ui.actionDroite,SIGNAL(triggered()), this, SLOT(selectViewPortRight())); + + connect(ui.actionMode_Normal,SIGNAL(triggered()), this, SLOT(toggleNormal())); + connect(ui.actionMode_SplitScreen,SIGNAL(triggered()), this, SLOT(toggleSplitScreen())); + connect(ui.actionMode_Fusion,SIGNAL(triggered()), this, SLOT(toggleFusion())); + + connect(ui.actionAfficher_Cacher_le_Rep_re,SIGNAL(triggered()), this, SLOT(viewerAxis())); + connect(ui.actionWireMode,SIGNAL(triggered()), this, SLOT(viewerWireMode())); + connect(ui.actionVider_la_Sc_ne, SIGNAL(triggered()), this, SLOT(fileCleanScene())); + connect(ui.actionReset_Camera, SIGNAL(triggered()), this, SLOT(toolCamReset())); + connect(ui.actionSelecteur, SIGNAL(triggered()), this, SLOT(toogleBorder())); + + connect(ui.actionToggleFPS,SIGNAL(triggered()), this, SLOT(toggleShowFps())); + connect(ui.actionInformation_Objet,SIGNAL(triggered()), this, SLOT(toggleInfo())); + + // Densité + connect(ui.actionCharger_la_Densite,SIGNAL(triggered()), this, SLOT(showDensity())); + + // Billboard + connect(ui.actionBillboard,SIGNAL(triggered()), this, SLOT(BB())); + connect(ui.actionBillboardCloud,SIGNAL(triggered()), this, SLOT(BBC())); + +}; + +void BBWindow::closeEvent(QCloseEvent *event) +{ + event->accept(); +#ifdef DEBUG + std::cout << "Quitter" << std::endl ; +#endif +} + +void BBWindow::createScene (void) +{ + Light *pLight; + Light *pLight2; + Light *pLight3; + + GLenum err = glewInit(); + if (GLEW_OK != err) + { + std::cout << "Erreur !! GlewInit : " << glewGetErrorString(err) << std::endl; + } else { + // On lance la suite ... + std::cout << "Utilisation de GLEW Version: " << glewGetString (GLEW_VERSION) << std::endl; + pLight = new Light (Light::LT_POINT); + pLight->setPosition (Vector3 (3., 5.,5.)); + pLight->setColor (Color (1.,1.,1.)); + + pLight2 = new Light (Light::LT_POINT); + pLight2->setPosition (Vector3 (3., -5.,-5.)); + pLight2->setColor (Color (1.,1.,1.)); + + pLight3 = new Light (Light::LT_POINT); + pLight3->setPosition (Vector3 (-5., 0.,0.)); + pLight3->setColor (Color (1.,1.,1.)); + + mScene->add (pLight, false); + mScene->add (pLight2, false); + mScene->add (pLight3, false); + + //// Scene deuxieme viewport ///// + mScene2->add (pLight, false); + mScene2->add (pLight2, false); + mScene2->add (pLight3, false); + ////////////////////////////////// +#ifdef DEBUG + std::cout << "Creation de la Scene : OK !" << std::endl ; +#endif + } +} + +void BBWindow::loadObjectDialog() +{ + QString fileName = QFileDialog::getOpenFileName(this, + "Choisissez un Objet à Charger", + "./../../branches/Objets", + tr("Tous les fichiers objet (*.3ds *.gts *.obj *.off *.ply *.bb *.bbc);;3D Studio files (*.3ds);;GNU Triangulated Surface (*.gts);;WaveFront model file (*.obj);;DEC Object File Format (*.off);;Stanford triangle format (*.ply);; ;;Tous les types Billboard (*.bb *.bbc);;Billboard (*.bb);;Billboard Cloud (*.bbc)"), 0,0); + if ( !fileName.isEmpty() ) + loadObject( fileName ); + else + ui.statusbar->showMessage( tr("Chargement annulé"), 0 ); +} + +void BBWindow::loadTextureDialog() +{ + bool ok= true; + if(numScene==1 && !mScene->isTextureEnable()) ok = false; + if(numScene==2 && !mScene2->isTextureEnable()) ok = false; + + if(ok){ + QString textureName = QFileDialog::getOpenFileName(this, + "Choisissez une texture à charger", + "../../branches/Objets/", + tr("Tous les fichiers image (*.bmp *.jpeg *.jpg *.png *.tga);; ;;Joint Photographic Experts Group (*.jpg *.jpeg);;PNG (*.png);; Windows BITMAP(*.bmp) ;; Truevision Targa (*.tga)"), 0,0); + if ( !textureName.isEmpty() ) + loadTexture( textureName ); + else + ui.statusbar->showMessage( tr("Chargement annulé"), 0 ); + } + else ui.statusbar->showMessage( tr("Chargement Impossible : Pas d'objet valide à texturer dans la scène."), 2000 ); +} + +void BBWindow::loadObject( const QString &fileName) +{ + timer(true); + Entity *pEntity; + Transform t; + Material *pMat; + numScene = mViewer->getViewport(); + + if(numScene==2 && mScene->isEmpty()) { + selectViewPortLeft(); + numScene=1; + } + + int mode =1; + if (ui.actionMode_Normal->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==2) mode =2; + + QFile f( fileName ); + if ( !f.open( QIODevice::ReadOnly ) ) + { + ui.statusbar->showMessage( tr("Chargement annulé"), 2000 ); + return; + } + // Test si l'objet à charger est un billboard cloud + if(fileName.contains(".bbc")) + { + bbc = new BillboardCloud(fileName,mViewer); + switch(numScene) + { + case 1: + mScene->remove(); + mScene->add(bbc); + mScene->setTextureEnable(false); + break; + case 2: + mScene2->remove(); + mScene2->add(bbc); + mScene2->setTextureEnable(false); + break; + } + bbc->setMode(mode,ui.actionInformation_Objet->isChecked()); + timer(false); + bbc->setTime(time); + } + // Test si l'objet à charger est un billboard + else if (fileName.contains(".bb")) + { + billbo = new Billboard(fileName,mViewer); + switch(numScene) + { + case 1: + mScene->remove(); + mScene->add(billbo); + mScene->setTextureEnable(false); + break; + case 2: + mScene2->remove(); + mScene2->add(billbo); + mScene2->setTextureEnable(false); + break; + } + billbo->setMode(mode,ui.actionInformation_Objet->isChecked()); + timer(false); + billbo->setTime(time); + } + // Chargement des autres objets + else + { + pEntity = new Mesh(fileName, "obj", ui.actionActiver_Desactiver_VBO->isChecked() + , mode); + t.setIdentity(); + t.setPosition(0., 0., 0.); + pEntity->setTransform(t); + pMat = new Material(); + pMat->setBaseColor(Color(0.8,0.6,0.5), 0.4); + pMat->setSpecular(Color::WHITE, 1); + pEntity->setMaterial(pMat); + if (numScene==1) + { + mScene->remove(); + mScene->add(pEntity); + mScene->setTextureEnable(true); + } + else + { + mScene2->remove(); + mScene2->add(pEntity); + mScene2->setTextureEnable(true); + } + ui.statusbar->showMessage( tr("Objet Chargé : ")+fileName, 0 ); + ui.menuBillboard->setEnabled(true); + ui.actionBillboard->setEnabled(true); + ui.actionBillboardCloud->setEnabled(true); + ui.actionSauvegarder->setEnabled(false); + } + ui.actionMode_SplitScreen->setEnabled(true); + ui.actionMode_Fusion->setEnabled(true); + + if (ObjIsAMesh()) ui.actionChargerTexture->setEnabled(true); + else ui.actionChargerTexture->setEnabled(false); + ui.menuViewport->setEnabled(true); + mViewer->maj(); +} + +void BBWindow::loadTexture(const QString &textureName) +{ + Entity *pEntity; + TextureLayer* pLayer; + Material *pMat; + numScene=mViewer->getViewport(); + + if (numScene==1) + { + pEntity=mScene->getByName("obj"); + } + else + { + pEntity=mScene2->getByName("obj"); + } + + pMat=pEntity->getMaterial(); + pLayer = new TextureLayer(textureName); + if (pMat->getNumberOfLayers()!=0) pMat->popTextureLayer(); + pMat->setBaseColor(Color::WHITE, 0.3); + pMat->pushTextureLayer(pLayer); + pMat->setAlphaRejection(0.5); + + pEntity->setMaterial(pMat); + if (numScene==1) + { + mScene->remove(false); + mScene->add(pEntity); + } + else + { + mScene2->remove(false); + mScene2->add(pEntity); + } + + ui.statusbar->showMessage( tr("Chargement de la Texture ")+textureName+" sur l'objet de la scène", 0 ); + mViewer->updateGL(); +} + + + +void BBWindow::viewerAxis() +{ + mViewer->setAxes(); + mViewer->updateGL(); +} + +void BBWindow::fileCleanScene() +{ + mScene->remove(); + mScene2->remove(); + mScene->setTextureEnable(false); + mScene2->setTextureEnable(false); + ui.actionChargerTexture->setEnabled(false); + + ui.actionMode_Normal->setChecked(true); + ui.actionMode_SplitScreen->setChecked(false); + ui.actionMode_Fusion->setChecked(false); + ui.actionMode_SplitScreen->setEnabled(false); + ui.actionMode_Fusion->setEnabled(false); + + ui.menuViewport->setEnabled(false); + ui.actionGauche->setChecked(true); + ui.actionDroite->setChecked(false); + + ui.menuBillboard->setEnabled(false); + ui.actionBillboard->setEnabled(false); + ui.actionBillboardCloud->setEnabled(false); + ui.actionSauvegarder->setEnabled(false); + + Camera *mpCamera = mViewer->getCamera() ; + mpCamera->reinit(0,0,0); + reinitViewPort(); + mViewer->updateGL(); + +} + +void BBWindow::toolCamReset() +{ + Camera *mpCamera = mViewer->getCamera() ; + //si la scene est vide on centre la camera sur le centre du repere + if(mScene->isEmpty()) mpCamera->reinit(0,0,0); + //sinon sur le centre de l'objet + else mViewer->maj(); + mViewer->updateGL(); +} + +void BBWindow::showDensity() +{ + int nbRowDensity; + bool ok; + int res = QInputDialog::getInteger(this, "Densité", "Taille de la matrice de densité",64, 4, 1024, 2,&ok,0); + if ( ok ) { + nbRowDensity=res; + } else { + nbRowDensity=0; + } + + if (nbRowDensity != 0 ) + { + DensityViewer * mm = new DensityViewer(nbRowDensity, ui.actionDensiteTex3D->isChecked(), mScene); + mm->show(); + } +} + +BBWindow::~BBWindow() +{ +} + + +void BBWindow::BB() +{ + //si l'objet de la scene peut etre texture alors il a un objet sur lequel on peur creer un Billboard + if(mScene->isTextureEnable()){ + bool ok=false; + int res = QInputDialog::getInteger(this, "Resolution", "resolution du billboard",512, 16, 512, 2,&ok,0); + if(ok){ + timer(true); + reinitViewPort(); + mScene->afficheInfo(4); + mViewer->modifAxes(false); + Density *densite = new Density(64); + Entity* pEntity = mScene->getEntity(); + int reso=2 ; + while ( reso < res) reso *= 2; + + std::vector vecto2; + densite->reset(); + mScene->fDensity( 4,densite); + densite->extractAllPlane(0.3,1,vecto2); + billbo = new Billboard(vecto2[0],pEntity,1.,mViewer,reso); + + timer(false); + billbo->setTime(time); + int mode =1; + if (ui.actionMode_Normal->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==2) mode =2; + billbo->setMode(mode,ui.actionInformation_Objet->isChecked()); + + numScene=1; + mViewer->selectViewPort(numScene); + mViewer->changeMode(1); + mScene2->remove(); + mScene2->add(billbo); + + ui.actionSauvegarder->setEnabled(true); + toggleSplitScreen(); + mScene->afficheInfo(5); + mViewer->maj(); + isBCC=false; + ui.actionChargerTexture->setEnabled(true); + } + } + else statusBar()->showMessage( tr("Pas d'objet valide dans la scène pour la construction"), 2000 ); +} + + +void BBWindow::BBC(){ + if(ui.actionBoite_Englobante->isChecked()) + { + BBCBox(); + return; + } + if(mScene->isTextureEnable()){ + timer(true); + bool ok=false; + int res = QInputDialog::getInteger(this, "Choix de résolution maximale", "résolution du billboardCloud",512, 16, 512, 2,&ok,0); + if(ok){ + ok = false; + int nbBB = QInputDialog::getInteger(this, "Choix du nombre de Billboards", "Combien de Billboards ?",50, 1, 500, 1,&ok,0); + if(ok){ + reinitViewPort(); + mScene->afficheInfo(4); + mViewer->modifAxes(false); + Density *densite = new Density(128); + Entity* pEntity = mScene->getEntity(); + int reso=2 ; + while ( reso < res) reso *= 2; + + std::vector vecto2; + densite->reset(); + int coverage = QInputDialog::getInteger(this, "Choix du coverage", "Quel coverage?",5, 1, 20, 1,&ok,0); + mScene->fDensity( coverage,densite); + densite->extractAllPlane(0.0001,nbBB,vecto2); + bbc = new BillboardCloud(pEntity,vecto2,mViewer,0.025,reso); + + timer(false); + bbc->setTime(time); + numScene=1; + mViewer->selectViewPort(numScene); + mViewer->changeMode(1); + mScene2->remove(); + mScene2->add(bbc); + int mode =1; + if (ui.actionMode_Normal->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==2) mode =2; + bbc->setMode(mode,ui.actionInformation_Objet->isChecked()); + + + ui.actionSauvegarder->setEnabled(true); + toggleSplitScreen(); + mScene->afficheInfo(5); + ui.actionChargerTexture->setEnabled(true); + isBCC=true; + mViewer->maj(); + } + } + } + else statusBar()->showMessage( tr("Pas d'objet valide dans la scène pour la construction"), 2000 ); +} + +void BBWindow::BBCBox(){ + if(mScene->isTextureEnable()){ + bool ok=false; + int res = QInputDialog::getInteger(this, "Choix de résolution maximale", "résolution du billboard",512, 16, 512, 2,&ok,0); + if(ok){ + timer(true); + reinitViewPort(); + mScene->afficheInfo(4); + + mViewer->modifAxes(false); + + std::vector vecto; + Entity* pEntity = mScene->getEntity(); + //pour la creation de la boite englobante + Billboard *bb = new Billboard(pEntity,mViewer); + + + float a,b,c,d,e,f,g,h,i,ap,bp,cp,dp; + // plan 1 + a=(bb->getBox()[0]).x; + b=(bb->getBox()[0]).y; + c=(bb->getBox()[0]).z; + d=(bb->getBox()[1]).x; + e=(bb->getBox()[1]).y; + f=(bb->getBox()[1]).z; + g=(bb->getBox()[2]).x; + h=(bb->getBox()[2]).y; + i=(bb->getBox()[2]).z; + + ap = b*f + e*i + h*c - f*h - i*b - c*e ; + bp = -(a*f + d*i + g*c - f*g - i*a - c*d); + cp = a*e + d*h + g*b - e*g - h*a - b*d; + dp = -(a*e*i + d*h*c + g*b*f - c*e*g - f*h*a - i*b*d); + + float fl[4] = {ap,bp,cp,dp}; + vecto.push_back(fl); + + // plan 2 + a=(bb->getBox()[0]).x; + b=(bb->getBox()[0]).y; + c=(bb->getBox()[0]).z; + d=(bb->getBox()[1]).x; + e=(bb->getBox()[1]).y; + f=(bb->getBox()[1]).z; + g=(bb->getBox()[7]).x; + h=(bb->getBox()[7]).y; + i=(bb->getBox()[7]).z; + + ap = b*f + e*i + h*c - f*h - i*b - c*e ; + bp = -(a*f + d*i + g*c - f*g - i*a - c*d); + cp = a*e + d*h + g*b - e*g - h*a - b*d; + dp = -(a*e*i + d*h*c + g*b*f - c*e*g - f*h*a - i*b*d); + + float fl2[4] = {ap,bp,cp,dp}; + vecto.push_back(fl2); + + //plan 3 + a=(bb->getBox()[3]).x; + b=(bb->getBox()[3]).y; + c=(bb->getBox()[3]).z; + d=(bb->getBox()[1]).x; + e=(bb->getBox()[1]).y; + f=(bb->getBox()[1]).z; + g=(bb->getBox()[7]).x; + h=(bb->getBox()[7]).y; + i=(bb->getBox()[7]).z; + + ap = b*f + e*i + h*c - f*h - i*b - c*e ; + bp = -(a*f + d*i + g*c - f*g - i*a - c*d); + cp = a*e + d*h + g*b - e*g - h*a - b*d; + dp = -(a*e*i + d*h*c + g*b*f - c*e*g - f*h*a - i*b*d); + + float fl3[4] = {ap,bp,cp,dp}; + vecto.push_back(fl3); + + //plan 4 + a=(bb->getBox()[4]).x; + b=(bb->getBox()[4]).y; + c=(bb->getBox()[4]).z; + d=(bb->getBox()[5]).x; + e=(bb->getBox()[5]).y; + f=(bb->getBox()[5]).z; + g=(bb->getBox()[7]).x; + h=(bb->getBox()[7]).y; + i=(bb->getBox()[7]).z; + + ap = b*f + e*i + h*c - f*h - i*b - c*e ; + bp = -(a*f + d*i + g*c - f*g - i*a - c*d); + cp = a*e + d*h + g*b - e*g - h*a - b*d; + dp = -(a*e*i + d*h*c + g*b*f - c*e*g - f*h*a - i*b*d); + + float fl4[4] = {ap,bp,cp,dp}; + vecto.push_back(fl4); + + //plan 5 + a=(bb->getBox()[0]).x; + b=(bb->getBox()[0]).y; + c=(bb->getBox()[0]).z; + d=(bb->getBox()[2]).x; + e=(bb->getBox()[2]).y; + f=(bb->getBox()[2]).z; + g=(bb->getBox()[6]).x; + h=(bb->getBox()[6]).y; + i=(bb->getBox()[6]).z; + + ap = b*f + e*i + h*c - f*h - i*b - c*e ; + bp = -(a*f + d*i + g*c - f*g - i*a - c*d); + cp = a*e + d*h + g*b - e*g - h*a - b*d; + dp = -(a*e*i + d*h*c + g*b*f - c*e*g - f*h*a - i*b*d); + + float fl5[4] = {ap,bp,cp,dp}; + vecto.push_back(fl5); + + //plan 6 + a=(bb->getBox()[2]).x; + b=(bb->getBox()[2]).y; + c=(bb->getBox()[2]).z; + d=(bb->getBox()[3]).x; + e=(bb->getBox()[3]).y; + f=(bb->getBox()[3]).z; + g=(bb->getBox()[4]).x; + h=(bb->getBox()[4]).y; + i=(bb->getBox()[4]).z; + + ap = b*f + e*i + h*c - f*h - i*b - c*e ; + bp = -(a*f + d*i + g*c - f*g - i*a - c*d); + cp = a*e + d*h + g*b - e*g - h*a - b*d; + dp = -(a*e*i + d*h*c + g*b*f - c*e*g - f*h*a - i*b*d); + + float fl6[4] = {ap,bp,cp,dp}; + vecto.push_back(fl6); + + int reso=2 ; + while ( reso < res) reso *= 2; + + bbc = new BillboardCloud(pEntity,vecto,mViewer,0.1,reso); + + timer(false); + bbc->setTime(time); + numScene=1; + mViewer->selectViewPort(numScene); + mViewer->changeMode(1); + mScene2->remove(); + mScene2->add(bbc); + int mode =1; + if (ui.actionMode_Normal->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==1) mode =0; + if (ui.actionMode_Fusion->isChecked() & numScene==2) mode =2; + bbc->setMode(mode,ui.actionInformation_Objet->isChecked()); + + ui.actionSauvegarder->setEnabled(true); + toggleSplitScreen(); + mScene->afficheInfo(5); + ui.actionChargerTexture->setEnabled(true); + isBCC=true; + mViewer->maj(); + } + } + else statusBar()->showMessage( tr("Pas d'objet valide dans la scène pour la construction"), 2000 ); +} + +void BBWindow::viewerWireMode(){ + + if (mViewer->isWireframeEnabled()) + mViewer->setWireframeEnabled(false); + else + mViewer->setWireframeEnabled(true); +} + +void BBWindow::statusChanged(const QString &message) +{ + ui.statusbar->showMessage( message, 0 ); +} + +void BBWindow::toggleShowFps(void) +{ + mShowFps = !mShowFps; + if(mShowFps) + { + connect(mViewer, SIGNAL(fpsChanged(const QString &)), this, SLOT(statusChanged(const QString &))); + } + else + { + disconnect(mViewer, SIGNAL(fpsChanged(const QString &)), this, SLOT(statusChanged(const QString &))); + ui.statusbar->showMessage( tr(" "), 0 ); + } + mViewer->updateGL(); +} + +void BBWindow::toogleBorder(void) +{ + mViewer->borderChange(); + mViewer->updateGL(); +} + +void BBWindow::toggleNormal(void) +{ + ui.actionMode_Normal->setChecked(true); + ui.actionMode_SplitScreen->setChecked(false); + ui.actionMode_Fusion->setChecked(false); + mViewer->changeMode(0); + + if(numScene==1){ + ui.actionGauche->setChecked(true); + ui.actionDroite->setChecked(false); + mScene->afficheInfo(2); + } + else{ + ui.actionGauche->setChecked(false); + ui.actionDroite->setChecked(true); + mScene2->afficheInfo(2); + } + mViewer->updateGL(); +} + +void BBWindow::toggleSplitScreen(void) +{ + if(ui.actionMode_SplitScreen->isEnabled()) + { + ui.actionMode_Normal->setChecked(false); + ui.actionMode_SplitScreen->setChecked(true); + ui.actionMode_Fusion->setChecked(false); + + ui.menuViewport->setEnabled(true); + + mViewer->changeMode(1); + + mScene->afficheInfo(1); + mScene2->afficheInfo(1); + mViewer->updateGL(); + } +} + +void BBWindow::toggleFusion() +{ + if(ui.actionMode_Fusion->isEnabled()) + { + ui.actionMode_Normal->setChecked(false); + ui.actionMode_SplitScreen->setChecked(false); + ui.actionMode_Fusion->setChecked(true); + + ui.menuViewport->setEnabled(true); + + mViewer->changeMode(2); + + mScene->afficheInfo(2); + mScene2->afficheInfo(3); + mViewer->updateGL(); + } +} + +void BBWindow::selectViewPortLeft(void) +{ + numScene=1; + mViewer->selectViewPort(numScene); + ui.actionDroite->setChecked(false); + if (ObjIsAMesh()) ui.actionChargerTexture->setEnabled(true); + else ui.actionChargerTexture->setEnabled(false); + mViewer->updateGL(); +} + +void BBWindow::selectViewPortRight(void) +{ + if(ui.menuViewport->isEnabled()) + { + numScene=2; + mViewer->selectViewPort(numScene); + ui.actionGauche->setChecked(false); + if (ObjIsAMesh()) ui.actionChargerTexture->setEnabled(true); + else ui.actionChargerTexture->setEnabled(false); + mViewer->updateGL(); + } +} + +void BBWindow::toggleInfo() +{ + mScene->afficheInfo(0); + mScene2->afficheInfo(0); + mViewer->updateGL(); +} + +void BBWindow::reinitViewPort(void) +{ + numScene=1; + mViewer->selectViewPort(numScene); + mViewer->changeMode(0); + ui.actionMode_SplitScreen->setChecked(false); + ui.actionMode_Fusion->setChecked(false); + ui.actionGauche->setChecked(true); + ui.actionDroite->setChecked(false); +} + +void BBWindow::SaveAs(void) +{ + if(!isBCC){ + QString filename; + QString fn = QFileDialog::getSaveFileName(this, "Enregistrer un Billboard","./../../branches/Objets/", + tr("Billboard (*.bb)"), 0,0); + if ( !fn.isEmpty() ) { + if(fn.contains(".bb")) filename=fn.section('.',0,0); + else filename = fn; + + QFile BBFile(filename.toAscii()+".png"); + if(BBFile.open(QIODevice::ReadOnly)) + { + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle("Conflit : Texture déjà présente"); + msgBox.setText("Attention, la texture liée à ce Billboard est déjà liée à un autre Billboard, voulez-vous continuer?"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + switch (msgBox.exec()) { + case QMessageBox::Yes: + break; + case QMessageBox::No: + return ; + break; + } + } + QFile f( filename+".bb" ); + if ( !f.open( QIODevice::WriteOnly ) ) { + statusBar()->showMessage( tr("Pas de droit d'écriture").arg(fn),2000 ); + return; + } + QTextStream t( &f ); + t << billbo->saveBillboard(filename) ; + f.close(); + } else { + statusBar()->showMessage( tr("Sauvegarde annulée"), 2000 ); + } + } + else{ + QString filename; + QString fn = QFileDialog::getSaveFileName(this, "Enregistrer un BillboardCloud","./../../branches/Objets/", + tr("BillboardCloud (*.bbc)"), 0,0); + if ( !fn.isEmpty() ) { + if(fn.contains(".bbc")) filename=fn.section('.',0,0); + else filename = fn; + + QFile BBFile(filename.toAscii()+".png"); + if(BBFile.open(QIODevice::ReadOnly)) + { + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle("Conflit : Texture déjà présente"); + msgBox.setText("Attention, la texture liée à ce Billboard Cloud est déjà liée à un autre Billboard ou Billboard Cloud, voulez-vous continuer?"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + switch (msgBox.exec()) { + case QMessageBox::Yes: + break; + case QMessageBox::No: + return ; + break; + } + } + + QFile f( filename+".bbc" ); + if ( !f.open( QIODevice::WriteOnly ) ) { + statusBar()->showMessage( tr("Pas de droit d'écriture").arg(fn),2000 ); + return; + } + QTextStream t( &f ); + t << bbc->saveBillboardCloud(filename) ; + f.close(); + } else { + statusBar()->showMessage( tr("Sauvegarde annulée"), 2000 ); + } + } +} + +bool BBWindow::ObjIsAMesh(void) +{ + Entity *pEntity; + if (numScene==1) + { + if(mScene->isEmpty()) return false; + pEntity=mScene->getEntity(); + } + else + { + if(mScene2->isEmpty()) return false; + pEntity=mScene2->getEntity(); + } + + if(pEntity->getName() == "obj" ) return true; + else return false; +} + +void BBWindow::timer(bool start) +{ + if(start) + { + debut = clock(); + fin = clock(); + } + else + { + fin = clock(); + time = (fin - debut) / CLOCKS_PER_SEC; + } +} + diff --git a/src/BBWindow.h b/src/BBWindow.h new file mode 100644 index 0000000..427e7a0 --- /dev/null +++ b/src/BBWindow.h @@ -0,0 +1,212 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 BBWindow_H +#define BBWindow_H + +#include + +#include + +#include "Light.h" +#include "Vector3.h" +#include "Entity.h" +#include "Material.h" +#include "TextureLayer.h" +#include "Mesh.h" +#include "Density.h" +#include "DensityViewer.h" +#include "Billboard.h" +#include "BillboardCloud.h" +#include "ui_W_Main.h" +#include "Viewer.h" +#include "Scene.h" +#include + + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + + class BBWindow :public QMainWindow +{ + Q_OBJECT + + public: +/** @name : BBWindow + * @brief : Constructeur + */ + BBWindow(); +/** @name : ~BBWindow + * @brief : Destructeur + */ + ~BBWindow(); + protected: + void closeEvent(QCloseEvent *event); +/** @name : loadObject + * @brief : chargement d'un objet maillé + * @param fileName : Nom du fichier + */ + void loadObject( const QString &fileName); + +/** @name : loadTexture + * @brief : chargement d'une texture sur l'objet courant + * @param textureName : Nom du fichier + */ + void loadTexture(const QString &textureName); + private slots: +/** @name : createScene + * @brief : Initialisation de la scène + */ + void createScene(void); + +/** @name : loadObjectDialog + * @brief : Affichage d'une boite de dialogue permettant le chargement des objets + */ + void loadObjectDialog(); + +/** @name : loadTextureDialog + * @brief : Affichage d'une boite de dialogue permettant le chargement des textures pour les objets maillé + */ + void loadTextureDialog(); + +/** @name : viewerAxis + * @brief : Active et désactive l'affichage du repère + */ + void viewerAxis(); + +/** @name : viewerWireMode + * @brief : Active/Désactive le mode filaire + */ + void viewerWireMode(); + +/** @name : fileCleanScene + * @brief : Efface la scène + */ + void fileCleanScene(); + + void toolCamReset(); +/** @name : showDensity + * @brief : Appel la fenêtre pour afficher la densité + */ + void showDensity(); + +/** @name : BB + * @brief : Crée un billboard + */ + void BB(); + +/** @name : BBC + * @brief : Crée un billboard cloud + */ + void BBC(); + +/** @name : BBCBox + * @brief : Crée un billboard cloud par rapport a la boite englobante de l'objet + */ + void BBCBox(); + +/** @name : statusChanged + * @brief : Affiche un message dans la barre de status + */ + void statusChanged(const QString &message); + +/** @name : toggleShowFps + * @brief : Active/Désactive l'affichage des FPS + */ + void toggleShowFps(void); + +/** @name : toggleNormal + * @brief : Active le mode Normal + */ + void toggleNormal(void); + +/** @name : toggleSplitScreen + * @brief : Active/Désactive le mode Split Screen(partage en 2 de l'écran) + * Cette fonction permet aussi de placer correctement l'affichage des + * informations en fonction du mode + */ + void toggleSplitScreen(void); + +/** @name : toggleFusion + * @brief : Active/Désactive le mode fusion + * Les 2 viewport sont l'un sur l'autre, l'un affiche sa partie droite, + * l'autre sa partie gauche. + * Cette fonction permet aussi de placer correctement l'affichage des + * informations en fonction du mode + */ + void toggleFusion(void); + +/** @name : selectViewPortLeft + * @brief : Selectionne le viewport de gauche + */ + void selectViewPortLeft(); + +/** @name : selectViewPortRight + * @brief : Selectionne le viewport de droite + */ + void selectViewPortRight(); + +/** @name : toggleInfo + * @brief : Active/Désactive l'affichage des informations à l'écran + */ + void toggleInfo(); + +/** @name : toogleBorder + * @brief : Active/Désactive l'affichage du cadre entourant le viewport + */ + void toogleBorder(); + +/** @name : SaveAs + * @brief : Sauvegarde d'un Billboard ou d'un Billboard cloud + * Si la variable save = true, l'objet a sauvegarder sera un Billboard + * Sinon ça sauvegardera un Billboard Cloud + */ + void SaveAs(); + private: +/** @name : reinitViewPort + * @brief : Réinitialise les viewport + */ + void reinitViewPort(void); + +/** @name : ObjIsAMesh + * @brief : Test si l'objet contenu dans le viewport courant est de type bb ou bbc + */ + bool ObjIsAMesh(void); + + Ui::MyWindow ui; + bool mShowFps; + Viewer *mViewer; + QDockWidget *mDensityWidget; + Scene *mScene; + Scene *mScene2; + BillboardCloud *bbc ; + int numScene; + Billboard * billbo; + bool isBCC; + + void timer(bool start); + double debut, fin; + double time; +}; + +#endif diff --git a/src/Billboard.cpp b/src/Billboard.cpp new file mode 100644 index 0000000..609dd14 --- /dev/null +++ b/src/Billboard.cpp @@ -0,0 +1,696 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 "Billboard.h" + + + +float Billboard::distVertices(Vector3 vect1,Vector3 vect2){ + return (sqrt((vect1.x - vect2.x)*(vect1.x - vect2.x)+(vect1.y - vect2.y)*(vect1.y - vect2.y)+(vect1.z - vect2.z)*(vect1.z - vect2.z))); +} + + +void Billboard::projection(std::vector vect){ + + float a = plan[0]; + float b = plan[1]; + float c = plan[2]; + float d = plan[3]; + + float xp,yp,zp; + if(a!=0.){ + xp=-d/a; + yp=0.; + zp=0.; + } + else if(b!=0.){ + xp=0.; + yp=-d/b; + zp=0.; + } + else { + xp=0.; + yp=0.; + zp=-d/c; + } + + //la projection + for(std::vector::iterator it=vect.begin();it &vect, std::vector &frame){ + + // calcul du centre du nuage de points + Vector3 center(0.,0.,0.); + for (unsigned int i=0; i= eigenValue[1]) { + if (eigenValue[0] >= eigenValue[2]) { + frame.push_back(eigenVector[0]); + if (eigenValue[1] >= eigenValue[2]) { + frame.push_back(eigenVector[1]); + frame.push_back(eigenVector[2]); + } else { + frame.push_back(eigenVector[2]); + frame.push_back(eigenVector[1]); + } + } else { + frame.push_back(eigenVector[2]); + frame.push_back(eigenVector[0]); + frame.push_back(eigenVector[1]); + } + } else { + if (eigenValue[1] >= eigenValue[2]) { + frame.push_back(eigenVector[1]); + if (eigenValue[0] >= eigenValue[2]) { + frame.push_back(eigenVector[0]); + frame.push_back(eigenVector[2]); + } else { + frame.push_back(eigenVector[2]); + frame.push_back(eigenVector[0]); + } + } else { + frame.push_back(eigenVector[2]); + frame.push_back(eigenVector[1]); + frame.push_back(eigenVector[0]); + } + } + + //les vecteurs propres ne forment pas un triède direct + + //creation du repere direct O XYZ + + //OZ + Vector3 v1 = frame[2] - center; + //O(-Z) + Vector3 v2 = (-frame[2]) - center; + + Vector3 centre = entity->getCenter(); + //OP + Vector3 Z = centre - center; + + //les cosinus des angles + float cosa = v1.dotProduct(Z) / sqrt(v1.squaredLength() * Z.squaredLength()); + float cosb = v2.dotProduct(Z) / sqrt(v2.squaredLength() * Z.squaredLength()); + //maj de Z + if(acos(cosa)>acos(cosb)) frame[2]=-frame[2]; + + Vector3 Y(frame[1].x + 0.1,frame[1].y + 0.1,frame[1].z + 0.1); + //calcul de Y par rapport a l'angle + float cosc = Y.dotProduct( frame[2]) / sqrt(Y.squaredLength() * frame[2].squaredLength()); + if(cosc<0.) frame[1] = -frame[1]; + + //produit vectoriel pour calculer X + frame[0].x = frame[2].y * frame[1].z - frame[2].z * frame[1].y; + frame[0].y = frame[2].z * frame[1].x - frame[2].x *frame[1].z; + frame[0].z = frame[2].x * frame[1].y - frame[2].y *frame[1].x; + + return center; +} + + +Vector3* Billboard::findCoord(Matrix4* repere ,std::vector vect){ + Vector3 res; + Vector3 minX,minY,maxX,maxY; + +//recherche du rectangle englobant + for(int j=0;j<3;j++){ + minX.x=vect[0].x; + minX.y=vect[0].y; + minX.z=vect[0].z; + + minY.x=vect[0].x; + minY.y=vect[0].y; + minY.z=vect[0].z; + + maxX.x=vect[0].x; + maxX.y=vect[0].y; + maxX.z=vect[0].z; + + maxY.x=vect[0].x; + maxY.y=vect[0].y; + maxY.z=vect[0].z; + } + + for(unsigned int i=1;ivect[i].x) { + minX.x=vect[i].x; + minX.y=vect[i].y; + minX.z=vect[i].z; + } + if(minY.y>vect[i].y) { + minY.x=vect[i].x; + minY.y=vect[i].y; + minY.z=vect[i].z; + } + + if(maxX.x vecto; + Vector3 v3; + + v3.x=minX.x; + v3.y=maxY.y; + v3.z=0.; + vecto.push_back(v3); + + v3.x=minX.x; + v3.y=minY.y; + v3.z=0.; + vecto.push_back(v3); + + v3.x=maxX.x; + v3.y=minY.y; + v3.z=0.; + vecto.push_back(v3); + + v3.x=maxX.x; + v3.y=maxY.y; + v3.z=0.; + vecto.push_back(v3); + + //on stocke aussi le centre + epsilon qui sera la position de la camera + res.x=(minX.x+maxX.x)/2.; + res.y=(minY.y+maxY.y)/2.; + res.z=-epsilon;//car Z pointe vers l'objet + + vecto.push_back(res); + + std::vector vectoInv; + for (std::vector::iterator it=vecto.begin(); it != vecto.end(); it++) { + // projection sur le plan + Vector3 v = *repere * (*it); + vectoInv.push_back(v); + } + //sauvegarde des coordonnees du billboard + std::vector::iterator r; + r=vectoInv.begin(); + + verticesBB[0]=(*r).x; + verticesBB[1]=(*r).y; + verticesBB[2]=(*r).z; + + r++; + verticesBB[3]=(*r).x; + verticesBB[4]=(*r).y; + verticesBB[5]=(*r).z; + r++; + verticesBB[6]=(*r).x; + verticesBB[7]=(*r).y; + verticesBB[8]=(*r).z; + r++; + verticesBB[9]=(*r).x; + verticesBB[10]=(*r).y; + verticesBB[11]=(*r).z; + + r=(vectoInv.end() -1); + //retourne la position de la camera + return &(*r); +} + +void Billboard::createBox(){ + + std::vector vect = entity->getVertexArrayE(); +//recherche de la boite englobante + Vector3 minX(vect[0]); + Vector3 maxX(vect[0]); + Vector3 minY(vect[0]); + Vector3 maxY(vect[0]); + Vector3 minZ(vect[0]); + Vector3 maxZ(vect[0]); + + + for(unsigned int i=1;ivect[i].x) minX=vect[i]; + if(minY.y>vect[i].y) minY=vect[i]; + if(minZ.z>vect[i].z) minZ=vect[i]; + if(maxX.xd1) distMaxBox = d2; + if(d3>distMaxBox) distMaxBox = d3; +} + +int Billboard::resolution(float a){ + if(a>0.5) return resMax; + else if(a>0.25) return resMax/2; + else return resMax/4; + +} + +void Billboard::createBillboard(){ + + //projette les sommets de la boite englobante sur le plan + projection(box); + std::vector frame; + + // on parametre le plan : ACP + centre + Vector3 center = acp(projections, frame); + + // on construit la matrice de changement de repere + Matrix4 mat( + frame[0][0], frame[1][0],frame[2][0], center[0], + frame[0][1], frame[1][1],frame[2][1], center[1], + frame[0][2], frame[1][2],frame[2][2], center[2], + 0., 0., 0., 1. + ); + + mat = mat.inverse(); + std::vector projections2D; + + for (std::vector::iterator it=projections.begin(); it != projections.end(); it++) { + // projection sur le plan + Vector3 v = mat * (*it); + projections2D.push_back(v); + } + mat = mat.inverse(); + + //sauvegarde des normales du Billboard + normals.x = -frame[2].x; + normals.y = -frame[2].y; + normals.z = -frame[2].z; + + + //parametrisation de la camera + + Vector3* position = findCoord(&mat,projections2D); + + cam->setPosition(*position); + + cam->setX(frame[0]); + cam->setY(frame[1]); + cam->setZ(frame[2]); + + //parametrisation de la camera pour la texture + float d1 = sqrt((verticesBB[0] - verticesBB[3])*(verticesBB[0] - verticesBB[3])+(verticesBB[1] - verticesBB[4])*(verticesBB[1] - verticesBB[4])+(verticesBB[2] - verticesBB[5])*(verticesBB[2] - verticesBB[5])); + + float d2 = sqrt((verticesBB[0] - verticesBB[9])*(verticesBB[0] - verticesBB[9])+(verticesBB[1] - verticesBB[10])*(verticesBB[1] - verticesBB[10])+(verticesBB[2] - verticesBB[11])*(verticesBB[2] - verticesBB[11])); + + + float rapportX,rapportY; + bool t=false; + if(d1>d2){ + rapportX = d1/distMaxBox; + rapportY = d2/distMaxBox; + t=true; + } + else{ + rapportY = d1/distMaxBox; + rapportX = d2/distMaxBox; + } + + vX = resolution(rapportX); + vY = resolution(rapportY); + + if(t) cam->setViewport2( vX,vY,d1,d2,epsilon); + else cam->setViewport2( vX,vY,d2,d1,epsilon); + //activation du glOrtho + cam->setPerspective(false); +} + + + +void Billboard::generateTexture(){ + pixels = new unsigned char[vX*vY*4]; + glReadBuffer(GL_BACK); + glReadPixels(0, 0,vX,vY, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glGenTextures(1, _textureID); + glBindTexture(GL_TEXTURE_2D, _textureID[0]); + gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,vX,vY,GL_RGBA,GL_UNSIGNED_BYTE,pixels); + glBindTexture(GL_TEXTURE_2D,0); + //desactivation du glOrtho,mode perspective + cam->setPerspective(true); +} + +void Billboard::drawGeometry(){ + + //affichage du billboard + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glEnable(GL_LIGHTING); + glEnable(GL_ALPHA_TEST); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, _textureID[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_LINEAR + glBegin(GL_QUADS); + glNormal3f(normals.x,normals.y,normals.z);glTexCoord2d(tCoord[0],tCoord[1]); glVertex3f(verticesBB[0],verticesBB[1],verticesBB[2]); + glNormal3f(normals.x,normals.y,normals.z); glTexCoord2d(tCoord[2],tCoord[3]); glVertex3f(verticesBB[3],verticesBB[4],verticesBB[5]); + glNormal3f(normals.x,normals.y,normals.z); glTexCoord2d(tCoord[4],tCoord[5]); glVertex3f(verticesBB[6],verticesBB[7],verticesBB[8]); + glNormal3f(normals.x,normals.y,normals.z); glTexCoord2d(tCoord[6],tCoord[7]); glVertex3f(verticesBB[9],verticesBB[10],verticesBB[11]); + glEnd(); + glDisable(GL_TEXTURE_2D); + + // le mode filiaire + if(viewer->isWireframeEnabled()){ + + glEnable(GL_POLYGON_SMOOTH ); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glLineWidth(1.5); + glBegin(GL_QUADS); + glVertex3f(verticesBB[0],verticesBB[1],verticesBB[2]); + glVertex3f(verticesBB[3],verticesBB[4],verticesBB[5]); + glVertex3f(verticesBB[6],verticesBB[7],verticesBB[8]); + glVertex3f(verticesBB[9],verticesBB[10],verticesBB[11]); + glEnd(); + } + if (Binfo) drawText(); +} + +Vector3 Billboard::getCenterM(void) +{ + Vector3 center; + center.x=(verticesBB[0]+verticesBB[3]+verticesBB[6]+verticesBB[9])/4.; + center.y=(verticesBB[1]+verticesBB[4]+verticesBB[7]+verticesBB[10])/4.; + center.z=(verticesBB[2]+verticesBB[5]+verticesBB[8]+verticesBB[11])/4.; + return center; +} + +std::vector Billboard::getVertexArray(){ + std::vector vect; + return vect; +} + + +Billboard::Billboard(float *vect,Entity* entite,float ep, Viewer*view,int res):entity(entite),cam(view->getCamera()),epsilon(ep),viewer(view),resMax(res),isLoad(false),error(false), Binfo(false){ + for(int i=0;i<4;i++) plan[i] = vect[i]; + tCoord[0] = 0.; + tCoord[1] = 1.; + tCoord[2] = 0.; + tCoord[3] = 0.; + tCoord[4] = 1.; + tCoord[5] = 0.; + tCoord[6] = 1.; + tCoord[7] = 1.; + viewer->setWireframeEnabled(false); + createBox(); + createBillboard(); + viewer->updateGL(); + generateTexture(); +} + + +Billboard::Billboard(Entity* entite, Viewer*view): entity(entite),cam(view->getCamera()),viewer(view),error(false), Binfo(false){ + createBox(); +} + +Billboard::Billboard(const QString& filename,Viewer *v):viewer(v),isLoad(true),error(false), Binfo(false){ + viewer->setWireframeEnabled(false); + QFile BBFile(filename); + if(!BBFile.open(QIODevice::ReadOnly)) + { + std::cerr << "erreur :chargement Billboard : " << filename.toStdString() << std::endl; + return; + } + QTextStream in(&BBFile); + QString header; + in>>header; + QString path=(filename.section(".bb",0,0))+".png"; + Image im; + im = chargeImage(path.toAscii()); + if (im == NULL) + { + error=true; + return; + } + + vX = imageGetWidth(im); + vY = imageGetHeight(im); + + glGenTextures(1, _textureID); + glBindTexture(GL_TEXTURE_2D, _textureID[0]); + gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,vX,vY,GL_RGBA,GL_UNSIGNED_BYTE,imageGetPixels(im)); + glBindTexture(GL_TEXTURE_2D,0); + int i=0; + while(i<12){ + verticesBB[i++]=header.toFloat(); + in>>header; + } + i=0; + while(!(in.atEnd())){ + normals[i++]=header.toFloat(); + in>>header; + } + tCoord[0] = 0.; + tCoord[1] = 1.; + tCoord[2] = 0.; + tCoord[3] = 0.; + tCoord[4] = 1.; + tCoord[5] = 0.; + tCoord[6] = 1.; + tCoord[7] = 1.; +} + + +Billboard::Billboard(Image im,Viewer *v,float *sommets,float *texCoord,Vector3 norm):viewer(v),normals(norm),isLoad(true),error(false), Binfo(false){ + viewer->setWireframeEnabled(false); + vX = imageGetWidth(im); + vY = imageGetHeight(im); + glBindTexture(GL_TEXTURE_2D, _textureID[0]); + gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,vX,vY,GL_RGBA,GL_UNSIGNED_BYTE,imageGetPixels(im)); + glBindTexture(GL_TEXTURE_2D,0); + for(int i=0;i<12;i++) verticesBB[i] = sommets[i]; + for(int i=0;i<8;i++) tCoord[i]=texCoord[i]; +} + + +void Billboard::drawBillboard(){ + drawGeometry(); +} + +void Billboard::fillDensity(int coverage, Density *pDensity){} + +void Billboard::deleteVBO(){} + +unsigned char * Billboard::getPixels(){ + return pixels; +} + +int Billboard::getnX(){ + return vX; +} + +int Billboard::getnY(){ + return vY; +} + +QString Billboard::saveBillboard(const QString &filename){ + QString body; + QString str; + body=body+getCoord(); + Image ima; + ima= creeImage(pixels,vX,vY,4); + imageSauvePng(ima,filename.toAscii()+".png"); + + return body; +} +QString Billboard::getCoord(){ + QString str,body; + for(int i=0;i<12;i++) { + body=body+str.setNum(verticesBB[i])+" "; + if(i%3==2) body=body+"\n"; + } + body=body+str.setNum(normals.x)+" "; + body=body+str.setNum(normals.y)+" "; + body=body+str.setNum(normals.z)+"\n"; + return body; +} + +std::vector Billboard::getBox(){ + return box; +} + + +/// Tout ce qui suit concerne l'affichage des informations + +void Billboard::drawText() +{ + char info[10]; + bool Ecolormat = glIsEnabled(GL_COLOR_MATERIAL); + bool Elight = glIsEnabled(GL_LIGHTING); + bool Etext = glIsEnabled(GL_TEXTURE_2D); + char strMsg[100] = {0}; + int taille; + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_TEXTURE_2D); + glPushMatrix(); + glLoadIdentity(); + if (error) + { + glColor3f(1.,0.2,0.2); + glRasterPos3f(position.x,position.y,position.z); + sprintf ( strMsg, "Erreur de chargement : Texture introuvable"); + //actionBoite_Englobante + for (unsigned int i=0;i +#include "Camera.h" +#include "Viewer.h" +#include "Image.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Matrix3.h" +#include "Matrix4.h" +#include +#include +#include +#include + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Billboard : public Entity +{ +public: + /** + @brief Construction d'un Billboard + @name Billboard + @param vect le plan du Billboard + @param entite l'objet à simuler + @param ep la distance entre le plan et les sommets qui vont être pris en compte pour la copie des textures + @param view le Viewer dans lequel on travaille + @param res la resolution maximum du billboard + */ + Billboard(float *vect, Entity* entite,float ep,Viewer *view,int res); + + /** + @brief Chargement d'un Billboard à partir d'un fichier par le biais de BillboardCloud. + @name Billboard + @param im contient la texture + @param v le Viewer dans lequel on travaille + @param sommets les coordonnees des sommets + @param texCoord les coordonnees de textures + @param norm la normale au plan + */ + Billboard(Image im,Viewer *v,float *sommets,float *texCoord,Vector3 norm); + /** + @brief Chargement d'un Billboard a partir d'un fichier texte. + @name Billboard + @param filename le fichier + @param v le Viewer dans lequel on travaille + */ + Billboard(const QString& filename,Viewer *v); + + /** + @brief Sert juste à recuperer la boite englobante de l'objet + @name Billboard + @param entite l'objet + @param view le Viewer dans lequel on travaille + */ + Billboard(Entity* entite, Viewer*view); + /** + @brief Calcul de la boite englobante de l'objet + @name createBox + */ + void createBox(); + /** + appele par BillboardCloud pour l'affichage + @name drawBillboard + */ + void drawBillboard(); + /** + @brief projection de points sur le plan du billboard + @name projection + @param vect les points à projetter + */ + void projection(std::vector vect); + /** + @brief Analyse en composante principales pour calculer le repere du plan + @name acp + @param vect les points projettes sur le plan + @param frame le repere du plan a calculer + @return le centre du Billboard + */ + Vector3 acp(const std::vector &vect, std::vector &frame); + + /** + @brief Calcule la distance entre deux sommets + @name distVertices + @param vect1 un sommet + @param vect2 un sommet + @return la distance entre ces deux sommets + */ + float distVertices(Vector3 vect1,Vector3 vect2); + /** + @brief Recherche des coordonnees du Billboard par rapport aux points projettés sur le plan + @name findCoord + @param repere le repere du plan + @param vertices les sommets + @return la position de la camera pour le placage des textures + */ + Vector3* findCoord(Matrix4* repere ,std::vector vertices); + /** + @brief Recupère la texture pour le Billboard + @name generateTexture + */ + void generateTexture(); + /** + @brief Création globale d'un billboard + @name createBillboard + */ + void createBillboard(); + /** + @brief Donne la resolution de texture par rapport à la longueur + @name resolution + @param a la distance entre 2 sommets + @return la resolution + */ + int resolution(float a); + /** + @name getPixels + @return renvoie la texture du Billboard + */ + unsigned char *getPixels(); + /** + @name getnX + @return renvoie la resolution du Billboard ppar rapport a sa largeur + */ + int getnX(); + /** + @name getnY + @return renvoie la resolution du Billboard ppar rapport a sa hauteur + */ + int getnY(); + /** + @name saveBillboard + @return les informations a sauvegarder + */ + QString saveBillboard(const QString &filename); + /** + @name getCoord + @return les cooordonnees du Billboard + */ + QString getCoord(); + /** + @name getBox + @return la boite englobante + */ + std::vector getBox(); + + /** @name setMode + * @brief Permet de définir le mode d'affichage en cour pour placer correctement les informations + * @param mode : le mode choisi + */ + void setMode(int mode, bool info); + + /** @name setTime + * @brief Affecte le temps passé à la création et au chargement du Billboard + * @param t : le temps passé + */ + void setTime(double t); + +protected : + + virtual void drawGeometry(void); + virtual Vector3 getCenterM(void); + virtual std::vector getVertexArray(); + virtual void deleteVBO(); + virtual void afficheInfoM(int split); + virtual void fillDensity(int coverage, Density *pDensity); + + /** + equation du plan + */ + float plan[4]; + /** + sommets du billboard a tracer + */ + float verticesBB[12]; + /** + distance qui sert de reference pour le calcul de la resolution de texture + */ + float distMaxBox; + /** + l'objet associe au billboard + */ + Entity* entity; + /** + la camera de la scene + */ + Camera *cam; + /** + identifiant de texture + */ + unsigned int _textureID[1]; + /** + la distance entre le plan et les sommets qui seront pris en compte lors du placage de la texture + */ + float epsilon; + /** + dimensions de la texture + */ + int vX,vY; + /** + le Viewer associe + */ + Viewer *viewer; + /** + la texture + */ + unsigned char *pixels; + /** + les sommets de la boite englobante projettes sur le plan + */ + std::vector projections; + /** + les coordonnees de textures + */ + float tCoord[8]; + /** + les normales du billboard + */ + Vector3 normals; + /** + la boite englobante + */ + std::vector box; + /** + resolution maximum du billboard + */ + int resMax; +private : + /// Fonction et variables utilisé pour l'affichage des informations + void drawText(void); + bool Binfo; + Vector3 position; + bool isLoad; + double time; + bool error; +}; + +#endif diff --git a/src/BillboardCloud.cpp b/src/BillboardCloud.cpp new file mode 100644 index 0000000..b305462 --- /dev/null +++ b/src/BillboardCloud.cpp @@ -0,0 +1,266 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 "BillboardCloud.h" + +BillboardCloud::BillboardCloud(Entity* entite,std::vector vect,Viewer*v,float ep,int reso): entity(entite),cam(v->getCamera()),viewer(v),isLoad(false), error(false), Binfo(false) +{ + //pour chaque plan on cree un Billboard + for(std::vector::iterator it = vect.begin();it!=vect.end();it++){ + Billboard *BB = new Billboard(*it, entity,ep,viewer,reso); + listBillboard.push_back(BB); + } +} + +BillboardCloud::BillboardCloud(const QString& filename,Viewer *v):viewer(v),isLoad(true), error(false), Binfo(false){ + QFile BBCFile(filename); + if(!BBCFile.open(QIODevice::ReadOnly)) + { + std::cerr << "erreur :chargement BillboardCloud : " << filename.toStdString() << std::endl; + return; + } + QTextStream in(&BBCFile); + QString header; + in>>header; + QString path=(filename.section(".bbc",0,0))+".png"; + Image im; + im = chargeImage(path.toAscii()); + if (im == NULL) + { + error=true; + return; + } + int nbBB = header.toInt(); + float texCoord[8]; + float coord[12]; + for(int i=0;i>header; + texCoord[j]=header.toFloat(); + } + for(int j=0;j<12;j++){ + in>>header; + coord[j]=header.toFloat(); + } + float f[3]; + for(int k=0;k<3;k++){ + in>>header; + f[k]=header.toFloat(); + } + Vector3 vect(f[0],f[1],f[2]); + Billboard *BB = new Billboard(im,viewer,coord,texCoord,vect); + listBillboard.push_back(BB); + } +} + + +BillboardCloud::~BillboardCloud(){ + +} + + +QString BillboardCloud::saveBillboardCloud(const QString &filename){ + QString body; + QString str; + + int count=0; + body=str.setNum(listBillboard.size())+"\n"; + while(!(filename.section('/',count,count)).isEmpty()) count++; + count--; + + int largeur=0,hauteur=0; + for(std::vector::iterator it=listBillboard.begin();it!=listBillboard.end();it++){ + if((*it)->getnX()>largeur) largeur = (*it)->getnX(); + hauteur += (*it)->getnY(); + } + unsigned char* image = new unsigned char[largeur * hauteur * 4]; + int h,l; + int index = 0; + float u,v,hauteurCourante=0.; + for(std::vector::iterator it=listBillboard.begin();it!=listBillboard.end();it++){ + l = (*it)->getnX() * 4; + h = (*it)->getnY(); + u=(l/4.)/largeur; + v=((float)h/(float)hauteur); + + hauteurCourante+=v; + + body=body+str.setNum(0.)+" "; + body=body+str.setNum(hauteurCourante)+"\n"; + + body=body+str.setNum(0.)+" "; + body=body+str.setNum(hauteurCourante - v)+"\n"; + + + body=body+str.setNum(u)+" "; + body=body+str.setNum(hauteurCourante-v)+"\n"; + + + body=body+str.setNum(u)+" "; + body=body+str.setNum(hauteurCourante)+"\n"; + + body=body+(*it)->getCoord(); + for(int i=0;igetPixels())[i*l+j]; + else if(j==l) image[index++]=((*it)->getPixels())[i*l+j-1]; + else image[index++] = 255; + } + + } + + } + Image ima; + ima= creeImage(image,largeur,hauteur,4); + imageSauvePng(ima,filename.toAscii()+".png"); + + return body; +} + +void BillboardCloud::drawGeometry(){ + for(std::vector::iterator it=listBillboard.begin();it!=listBillboard.end();it++){ + (*it)->drawBillboard(); + } + if (Binfo) drawText(); +} + + +Vector3 BillboardCloud::getCenterM(void) +{ + Vector3 center; + Vector3 centerBB; + std::vector::iterator ite; + float nb = (float)listBillboard.size(); + float x=0.,y=0., z=0.; + + for(std::vector::iterator it=listBillboard.begin();it!=listBillboard.end();it++) { + centerBB = (*it)->getCenter(); + x+= centerBB.x; + y+= centerBB.y; + z+= centerBB.z; + } + center.x=x/nb; + center.y=y/nb; + center.z=z/nb; + + return center; +} + +std::vector BillboardCloud::getVertexArray(){ + std::vector vect; + return vect; +} + + +void BillboardCloud::deleteVBO(){} + +void BillboardCloud::fillDensity(int coverage, Density *pDensity){} + + +/// Tout ce qui suit concerne l'affichage des informations + +void BillboardCloud::drawText() +{ + bool Ecolormat = glIsEnabled(GL_COLOR_MATERIAL); + bool Elight = glIsEnabled(GL_LIGHTING); + bool Etext = glIsEnabled(GL_TEXTURE_2D); + char strMsg[100] = {0}; + int taille; + char info[10]; + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_TEXTURE_2D); + glPushMatrix(); + glLoadIdentity(); + if (error) + { + glColor3f(1.,0.2,0.2); + glRasterPos3f(position.x,position.y,position.z); + sprintf ( strMsg, "Erreur de chargement : Texture introuvable"); + + for (unsigned int i=0;i + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class BillboardCloud : public Entity +{ +public: + /** + @name BillboardCloud + @brief Construction d'un BillboardCloud + @param entite l'objet a simuler + @param vect les plans des Billboards + @param ep la distance entre le plan et les sommets qui vont etre pris en compte pour la copie des textures + @param v le Viewer dans lequel on travaille + @param reso la resolution maximum des billboards + */ + BillboardCloud(Entity* entite,std::vector vect,Viewer *v,float ep,int reso); + /** + @name BillboardCloud + @brief Chargement d'un BillboardCloud a partir d'un fichier texte + @param filename le fichier + @param v le Viewer dans lequel on travaille + */ + BillboardCloud(const QString& filename,Viewer *v); + /** + @name saveBillboardCloud + @return les informations a sauvegarder + */ + QString saveBillboardCloud(const QString &filename); + + virtual ~BillboardCloud(); + + /** @name setMode + * @brief Permet de définir le mode d'affichage en cour pour placer correctement les informations + * @param mode : le mode choisi + */ + void setMode(int mode, bool info); + + /** @name setTime + * @brief Affecte le temps passé à la création et au chargement du Billboard + * @param t : le temps passé + */ + void setTime(double t); +protected: + + virtual void drawGeometry(void); + virtual Vector3 getCenterM(void); + virtual std::vector getVertexArray(); + virtual void deleteVBO(); + virtual void afficheInfoM(int mode); + virtual void fillDensity(int coverage, Density *pDensity); + + /** + l'objet associe au billboard + */ + Entity* entity; + + /** + la liste des Billboard + */ + std::vector listBillboard; + /** + la camera de la scene + */ + Camera *cam; + /** + le Viewer associe + */ + Viewer *viewer; + +private : + /// Fonction et variables utilisé pour l'affichage des informations + void drawText(void); + bool Binfo; + Vector3 position; + bool isLoad; + double time; + bool error; +}; + + + diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 0000000..375b1aa --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,226 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Camera.h" + +Camera::Camera() + : mCamX(1., 0., 0.), mCamY(0., 1., 0.), mCamZ(0., 0., -1.), + mPosition(0., 0., 2.), mDist(2.0), mFov(70.),mVectorUp(0., 1.0, 0.),mIsPerspective(true) +{ + mCamX.normalise(); + mCamY.normalise(); + mCamZ.normalise(); +} + + +Camera::Camera(const Vector3& viewDir, const Vector3& upDir, bool isPerspective) + : mCamY(upDir), mCamZ(viewDir), mDist(10.0), mFov(60.),mVectorUp(upDir),mIsPerspective(isPerspective) +{ + mCamZ.normalise(); + mCamX = mCamZ.crossProduct(mCamY); + mCamX.normalise(); + mCamY = mCamX.crossProduct(mCamZ); + mCamY.normalise(); + + mPosition = mCamZ*-10.0; +} + + +Camera::~Camera(){ +} + + +void Camera::renderGLStates() +{ + + // set the viewport + glViewport(mX, mY, mVpWidth, mVpHeight); + // set the projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + float ratio = (float)mVpWidth/(float)mVpHeight; + + if (mIsPerspective){ + + gluPerspective(mFov, ratio, 0.05, 10000.); + mCamX.normalise(); + mCamY.normalise(); + mCamZ.normalise(); + } + else{ + //initialise le viewport et le glOrtho pour recuperer la texture + glViewport(mX, mY, nX, nY); + glOrtho(-pX/2.,pX/2.,-pY/2., pY/2.,0., epsilon*2.); + + } + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + Vector3 target(mPosition); + target += mDist * mCamZ; + gluLookAt( + mPosition.x, mPosition.y, mPosition.z, + target.x, target.y, target.z, + mCamY.x, mCamY.y, mCamY.z); +} + +void Camera::setViewportSize(int posX, int posY, int width, int height) +{ + mVpWidth = width; + mVpHeight = height; + mX=posX; + mY=posY; +} +int Camera::getWidth(void) +{ + return mVpWidth; +} +int Camera::getHeight(void) +{ + return mVpHeight; +} + +Vector3& Camera::getPosition(void) +{ + return mPosition; +} + +void Camera::setPosition(const Vector3& v) +{ + mPosition = v; +} + +void Camera::setDist(const float v) +{ + mDist = v; +} + +void Camera::polarRotate(float dTheta, float dPhi) +{ + if (mIsPerspective) { + + Vector3 diff = - mDist * mCamZ; + Vector3 target = mPosition - diff; + + Quaternion q0, q1; + q0.FromAngleAxis(dTheta, mCamY); + q1.FromAngleAxis(-dPhi, mCamX); + diff = (q1 * q0) * diff; + + mPosition = target + diff; + + mCamZ = -diff; + mCamZ.normalise(); + mCamX = mCamZ.crossProduct(mCamY); + // projection de mCamX sur le plan horizontal + //mCamX -= mVectorUp * mCamX.dotProduct(mVectorUp); + mCamX.normalise(); + mCamY = mCamX.crossProduct(mCamZ); + mCamY.normalise(); + mCamX = mCamZ.crossProduct(mCamY); + mCamX.normalise(); + } +} + +void Camera::polarZoom(float d) +{ + if(mDist>d) + { + mDist -= d; + mPosition += mCamZ * d; + } +} + +void Camera::localTranslate(const Vector3& t) +{ + mPosition += mCamX * t.x; + mPosition += mCamY * t.y; + mPosition += mCamZ * t.z; + if (!mIsPerspective) + if(mDist>t.z) + mDist -= t.z; + +} + +void Camera::localRotate(float dTheta, float dPhi) +{ + if (mIsPerspective) { + Quaternion q0, q1; + q0.FromAngleAxis(-dTheta, mCamY); + q1.FromAngleAxis(dPhi, mCamX); + mCamZ = (q0*q1) * mCamZ; + + mCamZ.normalise(); + mCamX = mCamZ.crossProduct(mCamY); + // projection de mCamX sur le plan horizontal + mCamX -= mVectorUp * mCamX.dotProduct(mVectorUp); + mCamX.normalise(); + mCamY = mCamX.crossProduct(mCamZ); + mCamY.normalise(); + mCamX = mCamZ.crossProduct(mCamY); + mCamX.normalise(); + } +} + +void Camera::reinit(float tx, float ty, float tz) + +{ + mCamX=Vector3(1., 0., 0.); + mCamY=Vector3(0., 1., 0.); + mCamZ=Vector3(0., 0., -1.); + mPosition=Vector3(0., 0., 2.); + mPosition+=Vector3(tx, ty, tz); + mDist=2.0; + mFov=70.; + mVectorUp=Vector3(0., 1.0, 0.); +} + +void Camera::setPerspective( bool b){ + mIsPerspective=b; +} + + +/** Nom: getValCam + * Utilit? : Retourne les param?tres de la cam?ra + * Param?tres : Aucun + * Sortie : un vector de Vector3, contenant les param?tre de la cam?ra + * - mCamX + * - mCamY + * - mCamZ + * - mPosition + * - mDistance + */ +std::vector Camera::getValCam(void) +{ + std::vector res; + res.push_back(mCamX); + res.push_back(mCamY); + res.push_back(mCamZ); + res.push_back(mPosition); + res.push_back(Vector3(mDist,0.,0.)); + return res; +} + +void Camera::setX(const Vector3& v){ + mCamX=v; +} + +void Camera::setY(const Vector3& v){ + mCamY=v; +} + +void Camera::setZ(const Vector3& v){ + mCamZ=v; +} + + +void Camera::setViewport2(int x, int y, float a, float b, float c){ + nX=x; + nY=y; + pX=a; + pY=b; + epsilon=c; +} diff --git a/src/Camera.h b/src/Camera.h new file mode 100644 index 0000000..30d3359 --- /dev/null +++ b/src/Camera.h @@ -0,0 +1,89 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Camera_h_ +#define _Camera_h_ + +#include +#include +#include "Vector3.h" + + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + + +class Camera +{ +public: + + Camera(); + virtual ~Camera(); + Camera(const Vector3& viewDir, const Vector3& upDir, bool isPerspective = true); + virtual void renderGLStates(); + void setViewportSize(int posX, int posY, int width, int height); + int getWidth(void); + int getHeight(void); + void setPosition(const Vector3& v); + void setDist(const float v); + Vector3& getPosition(void); + std::vector getValCam(void); + void reinit(float tx, float ty, float tz); + void setPerspective(bool b); + /** + @name setX + @param v le nouveau vecteur X du repere camera + */ + void setX(const Vector3& v); + /** + @name setY + @param v le nouveau vecteur Y du repere camera + */ + void setY(const Vector3& v); + /** + @name setZ + @param v le nouveau vecteur Z du repere camera + */ + void setZ(const Vector3& v); + /** + @name setViewport2 + @param x largeur du viewport + @param y hauteur du viewport + @param a parametre pour la largeur du glOrtho + @param b parametre pour la hauteur du glOrtho + @param c parametre pour la profondeur du glOrtho + */ + void setViewport2(int x,int y, float a, float b,float c); + + virtual void polarRotate(float dTheta, float dPhi); + virtual void polarZoom(float d); + virtual void localTranslate(const Vector3& t); + virtual void localRotate(float dTheta, float dPhi); + protected: + Vector3 mCamX, mCamY, mCamZ; + Vector3 mPosition; + float mDist; + float mFov; + /** + les parametres du glOrtho + */ + float pX,pY,epsilon; + /** + les parametres du viewport + */ + int mVpWidth, mVpHeight,mX, mY,nX,nY; + Vector3 mVectorUp; + bool mIsPerspective; + +}; + +#endif + diff --git a/src/Color.cpp b/src/Color.cpp new file mode 100644 index 0000000..721b06d --- /dev/null +++ b/src/Color.cpp @@ -0,0 +1,18 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Color.h" + +const Color Color::WHITE(1., 1., 1., 1.); +const Color Color::BLACK(0., 0., 0., 1.); +const Color Color::RED(1., 0., 0., 1.); +const Color Color::GREEN(0., 1., 0., 1.); +const Color Color::BLUE(0., 0., 1., 1.); +const Color Color::YELLOW(1., 1., 0., 1.); +const Color Color::GREY30(0.3, 0.3, 0.3, 1.); +const Color Color::GREY50(0.5, 0.5, 0.5, 1.); +const Color Color::GREY80(0.8, 0.8, 0.8, 1.); diff --git a/src/Color.h b/src/Color.h new file mode 100644 index 0000000..6bdd8d2 --- /dev/null +++ b/src/Color.h @@ -0,0 +1,176 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Color_h_ +#define _Color_h_ + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Color +{ +public: + float r, g, b, a; + Color(float _r=1., float _g=1., float _b=1., float _a=1.) + : r(_r), g(_g), b(_b), a(_a) + { + } + Color(const Color& c) + { + r = c.r; + g = c.g; + b = c.b; + a = c.a; + } + inline Color& operator = ( const Color& c ) + { + r = c.r; + g = c.g; + b = c.b; + a = c.a; + return *this; + } + inline Color operator * (float f) const + { + Color c; + c.r = r * f; + c.g = g * f; + c.b = b * f; + c.a = a; + return c; + } + inline Color& operator *= (float f) + { + r *= f; + g *= f; + b *= f; + a *= f; + return *this; + } + inline Color& operator += (const Color& c) + { + r += c.r; + g += c.g; + b += c.b; + a += c.a; + return *this; + } + inline operator float* () + { + return &r; + } + inline operator const float* () const + { + return &r; + } + inline void fromLerp(float t, const Color& c0, const Color& c1) + { + float t1 = (1.-t); + r = t1*c0.r + t*c1.r; + g = t1*c0.g + t*c1.g; + b = t1*c0.b + t*c1.b; + a = t1*c0.a + t*c1.a; + } + inline void fromBGRA(unsigned long rgba) + { + r = ((float)(rgba>>16 & 0xff))/255.; + g = ((float)(rgba>>8 & 0xff))/255.; + b = ((float)(rgba>>0 & 0xff))/255.; + a = ((float)(rgba>>24 & 0xff))/255.; + } + inline void fromRGBA(unsigned long rgba) + { + r = ((float)(rgba & 0xff))/255.; + g = ((float)(rgba>>8 & 0xff))/255.; + b = ((float)(rgba>>16 & 0xff))/255.; + a = ((float)(rgba>>24 & 0xff))/255.; + } + inline void fromRGB(unsigned long rgba) + { + r = ((float)(rgba & 0xff))/255.; + g = ((float)(rgba>>8 & 0xff))/255.; + b = ((float)(rgba>>16 & 0xff))/255.; + a = 1.; + } + inline void fromBGR(unsigned long rgba) + { + b = ((float)(rgba & 0xff))/255.; + g = ((float)(rgba>>8 & 0xff))/255.; + r = ((float)(rgba>>16 & 0xff))/255.; + a = 1.; + } + inline unsigned long toRGBA(void) const + { + unsigned char val8; + unsigned long val32 = 0; + + // Convert to 32bit pattern + // (ABRG = 8888) + + // Alpha + val8 = (unsigned char)(a * 255); + val32 = val8 << 24; + + // Blue + val8 = (unsigned char)(b * 255); + val32 += val8 << 16; + + // Green + val8 = (unsigned char)(g * 255); + val32 += val8 << 8; + + // Red + val8 = (unsigned char)(r * 255); + val32 += val8; + + + return val32; + } + inline unsigned long toABGR(void) const + { + unsigned char val8; + unsigned long val32 = 0; + + // Convert to 32bit pattern + // (RGBA = 8888) + + // Red + val8 = (unsigned char)(r * 255); + val32 = val8 << 24; + + // Green + val8 = (unsigned char)(g * 255); + val32 += val8 << 16; + + // Blue + val8 = (unsigned char)(b * 255); + val32 += val8 << 8; + + // Alpha + val8 = (unsigned char)(a * 255); + val32 += val8; + + return val32; + } + + static const Color WHITE; + static const Color BLACK; + static const Color RED; + static const Color GREEN; + static const Color BLUE; + static const Color GREY30; + static const Color GREY50; + static const Color GREY80; + static const Color YELLOW; +}; + + +#endif diff --git a/src/Density.cpp b/src/Density.cpp new file mode 100644 index 0000000..9c54a15 --- /dev/null +++ b/src/Density.cpp @@ -0,0 +1,692 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotmail.fr * + * * + * 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 "Density.h" +#include "math.h" +#include +#include "Vector3.h" +#include "Matrix4.h" + +#include "textfile.h" + +#define Pi 3.1416 + +Density::Density(const int nbRow, bool UseTex3D) + :DRow(nbRow),DensityTex3D(UseTex3D),minAlpha(0.0) +{ + _textureID[0]=0; + if ( nbRow%2!=0 && (nbRow/2)%2 != 0 || nbRow<=0) { + std::cout << "Taille de matrice de densitée incorrecte ! La taille doit être une puissance de 2." << std::endl; + Data=NULL; + DRow=0; + } + else { + int nbCell = nbRow*nbRow*nbRow ; + Data = new float [nbCell]; // Allocation du tableau + for (int i=0; iremoveShaders(); + delete [] Data; + Data = NULL; + _textureID[0] = 0; +} + +int Density::getRow() +{ + return DRow; +} + + +float Density::getElt(int coord) +{ + return Data[coord]; +} +float Density::getElt(int x, int y, int z) +{ + int coord = (x+(DRow*y)+(z*DRow*DRow)); + return Data[coord] ; +} + + + +void Density::setElt(int x, int y, int z, float c) +{ + int coord = (x+(DRow*y)+(z*DRow*DRow)); + Data[coord]=c; +} + + +void Density::setElt(int coord, float c) +{ + Data[coord]=c; +} + + +void Density::fill(int x, int y, int z, float alphaAdd) // x y z +{ + float c = this->getElt(x,y,z); + c += alphaAdd ; + this->setElt(x,y,z,c); +} + + +void Density::reset() +{ + Density::reset(0.0f); +} + + +void Density::reset(const float defVal) +{ + int nbCell = DRow*DRow*DRow ; + for (int i=0; i actuellement trace une sphère creuse dans la matrice + * ajoute une division du volume en suivant une courbe d'équation cubique. + */ +void Density::InitTest() +{ + // dessine un cercle + int rayon = (int)(DRow*(DRow/sqrt(DRow))) ; + int centre = DRow/2 ; + int tmp ; + for(int i=0; i= rayon-centre) + setElt(i,j,k,0.95); + } +} + + +void Density::initDraw() +{ + glGenTextures(1, _textureID); // On génére la texture + + // On initialiser les shaders pour la coloration + setShaders(); + //InitTest(); + + // Si en texture 2D + if (!DensityTex3D) + { + glBindTexture(GL_TEXTURE_2D, _textureID[0]); + /*glTexImage2D ( GL_TEXTURE_2D, //GLenum target, + 0, //GLint level, + GL_RGBA, // GLint internalFormat, + DRow, // GLsizei width, + DRow*DRow, // GLsizei height, + 0, // GLint border, + GL_RGBA, // GLenum format, + GL_FLOAT, // GLenum type, + Data); // const GLvoid * data + */ + // On préfèrera les mipmaps pour pouvoir + // utiliser des textures de grande taille. + gluBuild2DMipmaps(GL_TEXTURE_2D, + GL_ALPHA, + DRow, + DRow*DRow, + GL_ALPHA, + GL_FLOAT, + Data); + + glBindTexture(GL_TEXTURE_2D,0); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);// Linear Filtering GL_NEAREST_MIPMAP_LINEAR. + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);// Linear Filtering GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } else { // Si en texture 3D + glBindTexture(GL_TEXTURE_3D, _textureID[0]); + glTexImage3D(GL_TEXTURE_3D, // enum target + 0, // int level + GL_ALPHA, // enum internalformat + DRow, + DRow, + DRow, + 0, // int border, + GL_ALPHA, // enum format + GL_FLOAT, // enum type, + Data); // const void* pixels + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_NEAREST GL_LINEAR + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_NEAREST GL_LINEAR + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } +} + + +void Density::drawDensity (Camera *camera) +{ + if (_textureID == 0) + std::cout << "drawDensity() : Draw's not initialized. Please run initDraw() before." << std::endl; + else + { + glDisable (GL_LIGHTING); + //glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR); + /* Alpha test : affiche les pixels qui ont un alpha suffisant */ + glEnable (GL_ALPHA_TEST); + glAlphaFunc (GL_GREATER, minAlpha); + /* BLENDING */ + glBlendFunc (GL_SRC_ALPHA,GL_ONE); + glEnable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + /* La couleur de la texture remplace la couleur par defaut*/ + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // GL_MODULATE GL_REPLACE + + /* crée les plans texturés */ + if (!DensityTex3D) + drawSlicesTex2D (camera); + else + drawSlicesTex3D (camera); + drawBorder(); + + glDisable (GL_ALPHA_TEST); + glDisable (GL_BLEND); + glEnable (GL_DEPTH_TEST); + } +} + + +void Density::drawSlicesTex2D(Camera *camera) +{ + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, _textureID[0]); + + double haut, bas, gauche, droite, pos; + double div=1.0/DRow; + double div1=2.0/(DRow-1); + + if ((camera->getPosition()).z > 0 ) + { + // Traçage : a partir du dernier plan vers le premier + haut=1. ; bas=1. ; gauche=0. ; droite=1.;pos = -1.0; + for (int i=DRow; i>0 ; i--) + { + bas=haut; + haut-=div; + + glBegin(GL_QUADS); + glNormal3i(0,0,1); + glTexCoord2d(gauche,bas); glVertex3f( -1.f, -1.f, pos); // 0,1 + glTexCoord2d(droite,bas); glVertex3f( 1.f, -1.f, pos); // 1,1 + glTexCoord2d(droite,haut); glVertex3f( 1.f, 1.f, pos);// 1,0 + glTexCoord2d(gauche,haut); glVertex3f( -1.f, 1.f, pos);// 0,0 + glEnd(); + pos+=div1; + } + } + else + { + // Traçage : a partir du premier plan vers le dernier + haut=0. ,bas=0. ,gauche=0.,droite=1., pos=1.; + for (int i=DRow; i>0 ; i--) + { + haut=bas; + bas+=div; + + glBegin(GL_QUADS); + glNormal3i(0,0,-1); + glTexCoord2d(gauche,bas); glVertex3f( -1.f, -1.f, pos); // 0,1 + glTexCoord2d(droite,bas); glVertex3f( 1.f, -1.f, pos); // 1,1 + glTexCoord2d(droite,haut); glVertex3f( 1.f, 1.f, pos);// 1,0 + glTexCoord2d(gauche,haut); glVertex3f( -1.f, 1.f, pos);// 0,0 + glEnd(); + pos-=div1; + } + } + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); +} + + +void Density::drawSlicesTex3D(Camera *cm) +{ + + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, _textureID[0]); + + float pos = 1.5; + //float pos = -0.8; + float div1=3./(DRow-1); + // le tableau des points a tracer : + Vector3 Ptab [6]; + Vector3 Ttab [6]; + int nbpoint = 0 ; + +for (int i=DRow; i>0 ; i--) + { + // on génére le polygone + generatePolygon(nbpoint, Ptab, Ttab, cm, pos); + // on le rend convexe + makeConvexPolygon(nbpoint,Ptab,Ttab); + // et on trace les points + glBegin(GL_POLYGON); + //glBegin(GL_LINE_LOOP); + glColor3ub(255,255,255); + //glNormal3i(0,0,1); + for (int i=0; i &temp) +{ + float maxtemp=32000; + + int j=1; + float* CoordMax=this->convertMaxPlane(); + + float max=CoordMax[4]; + + float *coord = new float[4]; + for(int i=0;i<4;i++) coord[i]=CoordMax[i]; + temp.push_back(coord); + + + while(alpha*max<=maxtemp && jconvertMaxPlane(); + + maxtemp=CoordMax[4]; + + float *coord = new float[4]; + for(int i=0;i<4;i++) coord[i]=CoordMax[i]; + + if(maxtemp>alpha) + temp.push_back(coord); + + j++; + } +} + +float* Density::convertMaxPlane() +{ + + + //initialisation + int dim=this->getRow(); + int suppress = 3; + float* carthMaxPlane=new float[5]; + + //recherche de la coordonnées du maximum + float* densityCoordMax=this->extractMaxPlane(/*0,0,0,dim*/); + + + for(int covOfX = -suppress; covOfX <= suppress; covOfX++) + { + for(int covOfY = -suppress; covOfY <= suppress; covOfY++) + { + for(int covOfZ = -suppress; covOfZ <= suppress*10/(this->getDistanceMax()); covOfZ++) + { + if( densityCoordMax[0]+covOfX=0 && densityCoordMax[1]+covOfY>=0 && densityCoordMax[2]+covOfZ>=0) + { + + int neighbourDist=abs(covOfX); + if(neighbourDistsetElt( (int) densityCoordMax[0]+covOfX, (int) densityCoordMax[1]+covOfY, + (int) densityCoordMax[2]+covOfZ,0.); + } + } + } + } + + float phi =( ((densityCoordMax[0]/(this->getRow()-1))*3.1416 ) + ( (densityCoordMax[0]+1)/(this->getRow()-1)*3.1416) )/2; + float ro =( ((densityCoordMax[1]/(this->getRow()-1))*3.1416*2+3.1416 ) + ( (densityCoordMax[1]+1)/(this->getRow()-1)*3.1416*2+3.1416) )/2; + + float a=sin(phi)*cos(ro); + + float b=sin(phi)*sin(ro); + float c=cos(phi); + float d= ( densityCoordMax[2]/(this->getRow()) )*( this->getDistanceMax() ); + + carthMaxPlane[0]=a; + carthMaxPlane[1]=b; + carthMaxPlane[2]=c; + carthMaxPlane[3]=d; + carthMaxPlane[4]=densityCoordMax[3]; + + return carthMaxPlane; +} + + + +float* Density::extractMaxPlane(){ + + float* planeMax=new float[4]; + planeMax[3]=0.; + for(int i=0;iDRow;i++) + { + for(int j=0;jDRow;j++) + { + for(int k=0;kDRow;k++) + { + float c = this->getElt(i,j,k); + if(planeMax[3] cam = cm->getValCam(); + Vector3 mCamZ = cam.at(3) ; + + mCamZ.normalise(); + + if (mCamZ.z != 0) + { + Ztab[0]= -(pos + mCamZ.x + mCamZ.y)/mCamZ.z ; // 1 1 + Ztab[1]= -(pos - mCamZ.x + mCamZ.y)/mCamZ.z ; // -1 1 + Ztab[2]= -(pos - mCamZ.x - mCamZ.y)/mCamZ.z ; // -1 -1 + Ztab[3]= -(pos + mCamZ.x - mCamZ.y)/mCamZ.z ; // 1 -1 + } + if (mCamZ.x != 0) + { + Xtab[0]= -(pos + mCamZ.y + mCamZ.z)/mCamZ.x ;// 1 1 + Xtab[1]= -(pos - mCamZ.y + mCamZ.z)/mCamZ.x ;// -1 1 + Xtab[2]= -(pos - mCamZ.y - mCamZ.z)/mCamZ.x ;// -1 -1 + Xtab[3]= -(pos + mCamZ.y - mCamZ.z)/mCamZ.x ;// 1 -1 + } + if (mCamZ.y != 0) + { + Ytab[0]= -(pos + mCamZ.x + mCamZ.z)/mCamZ.y ;// 1 1 + Ytab[1]= -(pos - mCamZ.x + mCamZ.z)/mCamZ.y ;// -1 1 + Ytab[2]= -(pos - mCamZ.x - mCamZ.z)/mCamZ.y ;// -1 -1 + Ytab[3]= -(pos + mCamZ.x - mCamZ.z)/mCamZ.y ;// 1 -1 + } + // on a calculé tout nos points, on filtres ceux qui correspondent a des points a tracer : + n=0; + for (int i=0 ; i < 4 ; i++) + { + if (Ztab[i]>-1 && Ztab[i]<=1) + { + Ptab[n]=Vector3(helpPtab1[i], helpPtab2[i], Ztab[i]); + Ttab[n]=Vector3(helpTtab1[i], helpTtab2[i], (Ztab[i]+1.)/2.); + n++; + } + if (Ytab[i]>-1 && Ytab[i]<=1) + { + Ptab[n]=Vector3(helpPtab1[i], Ytab[i], helpPtab2[i]); + Ttab[n]=Vector3(helpTtab1[i], (Ytab[i]+1.)/2., helpTtab2[i]); + n++; + } + if (Xtab[i]>-1 && Xtab[i]<=1) + { + Ptab[n]=Vector3(Xtab[i], helpPtab1[i], helpPtab2[i]); + Ttab[n]=Vector3((Xtab[i]+1.)/2., helpTtab1[i], helpTtab2[i]); + n++; + } + } + //on connait aussi le nombre de points a tracer + nbPoint = n ; +} + +void Density::makeConvexPolygon ( int n, Vector3 *Ptab, Vector3 *Ttab ) +{ + int helptab[6] = {0,-1,-1,-1,-1,-1}; //comporte le n° de sommets contenu dans Ptab mais ici ordonnée + int helptab2[6] = {0,-1,-1,-1,-1,-1}; //pour se souvenir quel vecteur est mis dans le contour + Vector3 centre = Vector3 ( 0,0,0 ) ; // centre de gravité des points + if ( n !=0 ) + { + for ( int i=0; i 0 && tmpnorm.x > 0) + &&(normale.y < 0 && tmpnorm.y< 0)||(normale.y > 0 && tmpnorm.y > 0) + &&(normale.z < 0 && tmpnorm.z< 0)||(normale.z > 0 && tmpnorm.z > 0)) + || normale == Vector3(0,0,0)) + { + min = tmp ; + place = i; + normale = tmpnorm; + } + } + } + } + // pour le prochain tour on partira du meilleur sommet + if ( place != -1 ) + { + vect1=Ptab[place]-centre; // le meilleur dernierement trouvé + helptab[j]=place; // on le met dans le contour a sa place + helptab2[place]=place; // et on se souvient qu'il est dans le contour + } + place = -1; + min = Pi; + } + // on place les points dans l'ordre de helptab + Vector3 tmptab[2][6] ; + for(int i=0 ; idistMax=dmax; +} + + +float Density::getDistanceMax() +{ + return this->distMax; +} diff --git a/src/Density.h b/src/Density.h new file mode 100644 index 0000000..a24ce8e --- /dev/null +++ b/src/Density.h @@ -0,0 +1,199 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 _Density_h_ +#define _Density_h_ + +#include +#include +#include +#include "Color.h" +#include "Camera.h" +#include + +/** Density class. Density + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + + +class Density +{ + public: + Density(const int nbRow, bool UseTex3D=false); + ~Density(); + + /** @name getElt + * Renvoie la valeur d'un élément de la matrice + * @param x : coordonné x de l'élément + * @param y : coordonné y de l'élément + * @param z : coordonné z de l'élément + * @return float + */ + float getElt(int x, int y, int z); + + /** @name getElt + * Renvoie la valeur d'un élément de la matrice + * @param coord : coordonné x de l'élément Attention il faut parcourir la matrice de 4 en 4. + * @return float + */ + float getElt(int coord); + /** @name setElt + * Attribue une valeur a un élément de la matrice + * @param x : coordonné x de l'élément + * @param y : coordonné y de l'élément + * @param z : coordonné z de l'élément + * @param c : la valeur + */ + void setElt(int x, int y, int z, float elt); + + /** @name setElt + * Attribue une valeur a un élément de la matrice + * @param coord : coordonné de l'élément (ici la matrice est considérée comme un long tableau) + * @param c : la valeur + */ + void setElt(int coord, float c); + + /** @name fill + * Remplis un élément de la matrice en incrémentant l'alpha + * @param x : coordonné x de l'élément + * @param y : coordonné y de l'élément + * @param z : coordonné z de l'élément + * @param alphaAdd : intensité à ajouter à l'alpha + */ + void fill(int x, int y, int z, float alphaAdd); + + /** @name setDistanceMax + * Définit le plan de l'objet le plus éloigné du centre, cela est nécessaire pour remplir la matrice de densité + * @param dmax : valeur de cette distance maximale + */ + void setDistanceMax(float dmax); + + + /** @name getDistanceMax + * Restitue la valeur de la distance maximale d'un plan cela est nécessaire lors de l'extraction du maximum + * afin de retrouver notre équation de plan + * @return this->distMax : la valeur de la distance maximum + */ + float getDistanceMax(); + + /** + * @name convertMaxPlane + * @brief Récupère le plan d'intensité maximal + * @return maxPlane : le plan d'intensité maximale + */ + float* convertMaxPlane(); + + /** + * @name extractAllMaxPlane + * @brief Récupère les plans d'intensité maximal + * @param alpha : valeur limite pour extraire un plan en tant que plan max + * @param billboard : nombre de plan max à retirer + * @param listMaxPlan : la liste de tous les plans max (vide a l'origine) + */ + void extractAllPlane(float alpha,int billboard, std::vector &listMaxPlan); + + /** @name getRow + * Retourne la taille de la Densité + */ + int getRow(); + + /** + * @name reset + * Toutes les valeurs de la densité sont mis a 0.0 + */ + void reset(); + + /** + * @name reset + * Permet de remplir la densité avec une valeur par defaut + * @param defVal : valeur de remplissage + */ + void reset(float defVal); + + /** @name initDraw + * Crée les textures necessaires pour le rendu. + */ + void initDraw(); + + /** + * @name drawDensity + * @brief Trace la densité + * @param camera : La camera de la scéne -> permet de récupérer sa positon + */ + void drawDensity(Camera *camera); + + /** + * @name setMinAlpha + * modifie la valeur alpha du blending lors de + * l'affichage de la densité + */ + void setMinAlpha(float minf); + + // Provisoire + void InitTest(); + + void removeShaders(); + private : + + /** + * @name extractMaxPlane + * @brief Récupère le plan d'intensité maximal de la matrice de densité + * @return MaxPlane : le plan d'intensité maximale + */ + float* extractMaxPlane(); + + /** + * @name drawSlicesTex2D + * Trace des Slices de la matrice de densité en utilisant une texture 2D + * Les slices sont ordonnées pour être tracé du plus loin au plus prés. + */ + void drawSlicesTex2D(Camera *camera); + + /** + * @name drawSlicesTex3D + * Trace des slices dans le Volume de la texture 3D + * @param c : camera. + */ + void drawSlicesTex3D(Camera *camera); + + /** + * @name drawBorder + * Trace un cadre autout de la Densité + * en jaune : le cotés des tranches + * en rouge : quand on est en face + */ + void drawBorder(); + void generatePolygon(int & n, Vector3 *Ptab, Vector3 *Ttab, Camera *cm, float pos); + void makeConvexPolygon(int n, Vector3 *Ptab, Vector3 *Ttab); + void coloring(); + void setShaders(); + protected: + int DRow; + bool DensityTex3D ; + GLfloat minAlpha ; + float * Data; + unsigned int _textureID[1]; + GLuint mTexId; + GLuint mVertShader, mFragShader, mProgShader; + float distMax; +}; +#endif diff --git a/src/DensityViewer.cpp b/src/DensityViewer.cpp new file mode 100644 index 0000000..98fd8e7 --- /dev/null +++ b/src/DensityViewer.cpp @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 "DensityViewer.h" + +DensityViewer::DensityViewer(int nbRowDensity, bool isT3D, Scene *parentScene) + :QMainWindow(), mShowFps(false), mDensityWidget(NULL), pScene(parentScene), numScene(1), pDensity(NULL), isTex3D(isT3D) +{ + ui.setupUi(this); + + // Init QGL + QGLFormat format; + format.setDoubleBuffer(true); + format.setDepth(true); + format.setRgba(true); + format.setAlpha(true); + format.setStencil(true); + format.setStereo(false); + QGLFormat::setDefaultFormat(format); + + // Chargement viewer en fenètre Main + mViewer = new Viewer(this); + mViewer->setFocus(); + setCentralWidget(mViewer); + // Attachement d'une scène au viewer + mScene = new Scene(); + + mViewer->attachScene(mScene, NULL); + + // Création de la densité + Density * pDensity = new Density(nbRowDensity, isTex3D); + // Création de la densité de l'objet + pScene->fDensity(0,pDensity); + attacheDensity(pDensity); + mViewer->setRotatePossible( false); + // /!\ Ne Pas Modifier la fenètre ICI ! Utiliser QtDesigner et le .ui ! + // Action de la fenêtre Main + connect(mViewer, SIGNAL(glInitialized()), this, SLOT(createScene())); + connect(ui.actionExit, SIGNAL(triggered()), this, SLOT(exit())); + connect(ui.actionDensityON,SIGNAL(triggered()), this, SLOT(showDensity())); + connect(ui.actionDensityOFF,SIGNAL(triggered()), this, SLOT(removeDensity())); +} + +void DensityViewer::closeEvent(QCloseEvent *event) +{ + (mDensityWidget->widget())->close(); + removeDockWidget(mDensityWidget); + mViewer->setRotatePossible(true); + this->removeDensity(); + event->accept(); +} + +void DensityViewer::exit() +{ + this->removeDensity(); + this->hide(); +} + +void DensityViewer::createScene (void) +{ + GLenum err = glewInit(); + if (GLEW_OK != err) + { + std::cout << "Erreur !! GlewInit : " << glewGetErrorString(err) << std::endl; + } + + showDensity(); +} + + +/** Nom: fileCleanScene + * Fct : efface la scène + */ +void DensityViewer::fileCleanScene() +{ + mScene->remove(); + Camera *mpCamera = mViewer->getCamera() ; + mpCamera->reinit(0,0,0); + numScene=1; + mViewer->selectViewPort(numScene); + mViewer->changeMode(0); + mViewer->updateGL(); +} + + +/** Nom: showDensity + * Fct : Appel la fenêtre pour afficher la densité + */ +void DensityViewer::showDensity() +{ + + if (pDensity != NULL ) + { + //mScene->fDensity(0,pDensity); + pDensity->initDraw(); + mViewer->freeDensity(); + mViewer->attachDensity(pDensity); + + //Ajout d'un widget + mDensityWidget = new QDockWidget("Densité minimale", this,0); + mDensityWidget->setFloating(true); + QDoubleSpinBox *w = new QDoubleSpinBox(mDensityWidget); + w->setValue(0); + w->setRange(0,1); + w->setSingleStep(0.01); + mDensityWidget->setWidget(w); + addDockWidget(Qt::RightDockWidgetArea, mDensityWidget); + + connect(w, SIGNAL(valueChanged(double)), this, SLOT(alphaChange(double))); + } +} + +void DensityViewer::alphaChange(double d) +{ + pDensity->setMinAlpha((float)d); + mViewer->updateGL(); +} + + +/** Nom : removeDensity + * Fct : Efface la densité + */ +void DensityViewer::removeDensity() +{ +// mViewer->freeDensity(); +// mViewer->updateGL(); + if (pDensity!=NULL) + { + delete pDensity; + } + pDensity=NULL; + + if (mScene!=NULL) + { + delete mScene; + } + mScene=NULL; + + if (mViewer!=NULL) + { + delete mViewer; + } + mViewer=NULL; +} + +DensityViewer::~DensityViewer() +{ + this->removeDensity(); +} + +void DensityViewer::attacheDensity(Density * mDensity) +{ + pDensity = mDensity; +} diff --git a/src/DensityViewer.h b/src/DensityViewer.h new file mode 100644 index 0000000..b607e3b --- /dev/null +++ b/src/DensityViewer.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * * + * 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 DENSITYVIEWER_H +#define DENSITYVIEWER_H + +#include + +#include +#include "Light.h" +#include "Vector3.h" +#include "Entity.h" +#include "Material.h" +#include "TextureLayer.h" +#include "Mesh.h" +#include "Density.h" +#include "ui_W_Density.h" +#include "Viewer.h" +#include "Scene.h" + + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + + +class DensityViewer :public QMainWindow +{ + Q_OBJECT + + public: + DensityViewer(int nbRowDensity, bool isT3D, Scene *parentScene); + ~DensityViewer(); + void attacheDensity(Density * pDensity); + + protected: + void closeEvent(QCloseEvent *event); + private slots: + void createScene(void); + void fileCleanScene(); + void showDensity(); + void removeDensity(); + void alphaChange(double d); + void exit(); + private: + Ui::DensityWindow ui; + bool mShowFps; + Viewer *mViewer; + QDockWidget *mDensityWidget; + Scene *mScene, *pScene; + Entity *bbc ; + int numScene; + Density * pDensity; + bool isTex3D; +}; + +#endif diff --git a/src/Entity.cpp b/src/Entity.cpp new file mode 100644 index 0000000..e551d0a --- /dev/null +++ b/src/Entity.cpp @@ -0,0 +1,134 @@ + +#include "Entity.h" +#include "Material.h" + + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +uint Entity::msEntitiesCount = 0; + +Entity::Entity(const QString& name) + : mName(name), mpMaterial(&Material::Default) +{ + if(mName=="") + { + mName = QString("Object%1").arg(msEntitiesCount++); + } + thetaX=0.; + thetaY=0.; + thetaZ=0.; +} +//-------------------------------------------------------------------------------- +Material* Entity::getMaterial(void) const +{ + return mpMaterial; +} +void Entity::setMaterial(Material* mat) +{ + mpMaterial = mat; +} +//-------------------------------------------------------------------------------- +void Entity::setTransform(const Transform& t) +{ + mTransform = t; +} +const Transform& Entity::getTransform(void) +{ + return mTransform; +} +void Entity::applyTransform(void) const +{ + mTransform.multCurrentMatrix(); +} +//-------------------------------------------------------------------------------- +void Entity::render(bool activateMaterial /* = true */) +{ + float tmpX=getCenter()[0],tmpY=getCenter()[1],tmpZ=getCenter()[2]; + + mpMaterial->activate(!activateMaterial); + glPushMatrix(); + + mTransform.multCurrentMatrix(); + + glTranslatef(tmpX,tmpY,tmpZ); + glRotatef (thetaX,1.,0.,0.); + glRotatef (thetaY,0.,1.,0.); + glRotatef (thetaZ,0.,0.,1.); + glTranslatef(-tmpX,-tmpY,-tmpZ); + + drawGeometry(); + + glPopMatrix(); + + mpMaterial->release(!activateMaterial); +} + +Vector3 Entity::getCenter(void) +{ + return getCenterM(); +} + +/** Nom: Rotation + * Utilité : Effectue une rotation a l'aide du clic droit de la souris + * Paramètres : dx : mouvement horizontale de la souris + * dy : mouvement verticale de la souris + * camParam : Paramètres de la caméra : + * camParam[0] : mCamX + * camParam[1] : mCamY + * camParam[2] : mCamZ + * camParam[3] : mPosition + * camParam[4][camParam[3]0] : mDist + * Sortie : l'objet à effectué une rotation + */ +void Entity::Rotation(float dx, float dy, std::vector camParam) +{ + if(camParam[3][0]*camParam[3][0] > camParam[3][2]*camParam[3][2]) + thetaZ+=camParam[2][0]*dy*-30.; + else + thetaX+=camParam[0][0]*dy*-30.; + + thetaY+=dx*30.; + + if (thetaX>360.) thetaX=0.; + if (thetaY>360.) thetaY=0.; + if (thetaZ>360.) thetaZ=0.; + if (thetaX<0.) thetaX=360.; + if (thetaY<0.) thetaY=360.; + if (thetaZ<0.) thetaZ=360.; + +} + +std::vector Entity::getVertexArrayE(){ + return getVertexArray(); +} + +/** Nom : deleteMesh + * Fct : détruit le VBO lors de la suppression d'une Mesh + */ +void Entity::deleteMesh(){ + deleteVBO(); +} + + +/** Nom : afficheInfo + * Fct : Appel la fonction pour afficher les informations à l'écran + * @param split: Indique quel mode est activée + * (normal=0, split screen=1, fusion(viewport 1)=2, fusion(viewport 2)=3) + */ +void Entity::afficheInfo(int split){ + afficheInfoM(split); +} + +/** Nom : fDensity + * Fct : Appel la fonction pour créer la matrice de densité d'un objet + * @param coverage : indice de couverture + * @param pDensity : matrice de densité + */ +void Entity::fDensity(int coverage, Density *pDensity) +{ + fillDensity(coverage, pDensity); +} diff --git a/src/Entity.h b/src/Entity.h new file mode 100644 index 0000000..84862c8 --- /dev/null +++ b/src/Entity.h @@ -0,0 +1,83 @@ +#ifndef _Entity_h_ +#define _Entity_h_ + + +#include +#include "Transform.h" +#include +#include +#include "Vector3.h" +#include "Density.h" + +class Material; + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + + +/** Classe abstraite représentant un objet dans la scène. + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Entity +{ +public: + + Entity(const QString& name = ""); + + virtual ~Entity() {}; + + inline const QString& getName(void) const + { + return mName; + } + float thetaX,thetaY,thetaZ; + Material* getMaterial(void) const; + void setMaterial(Material* mat); + + void setTransform(const Transform& t); + const Transform& getTransform(void); + void applyTransform(void) const; + + void Rotation(float dTheta, float dPhi, std::vector camParam); + /** méthode à appeler pour tracer l'objet + */ + virtual void render(bool activateMaterial = true); + virtual Vector3 getCenter(void); + virtual std::vector getVertexArrayE(); + virtual void deleteMesh(void); + void afficheInfo(int split); + void fDensity(int coverage, Density *pDensity); +protected: + + /** Méthode chargée du tracée de la géométrie de l'objet. + */ + virtual void drawGeometry(void) = 0; + virtual Vector3 getCenterM(void)=0; + virtual std::vector getVertexArray()=0; + virtual void deleteVBO() = 0; + virtual void afficheInfoM(int split) = 0; + virtual void fillDensity(int coverage, Density *pDensity)=0; + QString mName; + + /** Stock le matériau de l'objet. + Un mére materiau peut être partagée entre plusieurs objets. + */ + Material* mpMaterial; + + /** Position, orientation et mise à l'echelle de l'objet. + */ + Transform mTransform; + + static uint msEntitiesCount; + +}; + + +#endif diff --git a/src/Image.cpp b/src/Image.cpp new file mode 100644 index 0000000..f507293 --- /dev/null +++ b/src/Image.cpp @@ -0,0 +1,438 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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. * + ***************************************************************************/ +/*-------------------------------------------------------------------- + -- Introduction a OpenGL + -- Master 1 Informatique + -- UPS + -- + -- Mathias Paulin 2006 + -- + -------------------------------------------------------------------*/ + +#include "Image.h" + +#include + +#include +#include + +#include + + +#include +#include + +/*------------------------------------------------------------------*/ +/* Definition du type complet */ + + +typedef struct _image { + int width; + int height; + int depth; + unsigned char *pixels; +} internalImageRepresentation; + +/*------------------------------------------------------------------*/ +/* fonctions de chargement d'une image */ + +/*------------------------------------------------------------------*/ + + +/*------------------------------------------------------------------*/ +/* PNG support */ +static double get_gamma_exp(void) +{ + static double default_exponent = 2.2; + static int set = 0; + if (! set) + { + #if defined(NeXT) + default_exponent = 1.0; + #elif defined(sgi) + FILE *infile; + default_exponent = 1.3; + if (infile = fopen("/etc/config/system.glGammaVal", "r")) + { + double sgi_gamma; + char fooline[80]; + fgets(fooline, sizeof(fooline), infile); + fclose(infile); + sgi_gamma = atof(fooline); + if (sgi_gamma > 0.0) + default_exponent = 2.2 / sgi_gamma; + } + #elif defined(Macintosh) + default_exponent = 1.5; + #endif + set = 1; + } + return default_exponent; +} + +int loadPng(internalImageRepresentation *imageDest, const char *localFileName) +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + int bytes_per_row, row; + int gray_palette; + unsigned char *pixels = 0, **rows = 0; + unsigned int i; + + FILE *fp=fopen(localFileName,"rb"); + if (fp==NULL) return 0; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + + if (png_ptr == NULL) return 0; + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return 0; + } + + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + if (pixels) free(pixels); + if (rows) free(rows); + + return 0; + } + + png_init_io(png_ptr, fp); + + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + + imageDest->depth = png_get_channels(png_ptr, info_ptr); + + png_set_strip_16(png_ptr); + + png_set_packing(png_ptr); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_set_expand(png_ptr); + imageDest->depth = 3; + } + + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + { + png_set_expand(png_ptr); + ++(imageDest->depth); + } + + gray_palette = 0; + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + int n, num_palette; + png_colorp palette; + if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) + { + gray_palette = 1; + for (n=0; ndepth * width; + + pixels = (unsigned char*) malloc(bytes_per_row * height); + rows = (unsigned char**) malloc(height * sizeof(char *)); + if (pixels == 0 || rows == 0) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + return 0; + } + + for (row=0; row<(int)height; ++row) + rows[row] = &pixels[row * bytes_per_row]; + + png_read_image(png_ptr, rows); + + png_read_end(png_ptr, info_ptr); + + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + free(rows); + + if (gray_palette) + { + int n, np = width * height; + if (imageDest->depth == 3) + { + for (n=1; ndepth = 1; + } + else if (imageDest->depth == 4) + { + for (n=0; ndepth = 2; + } + } + + imageDest->width = width; + imageDest->height = height; + imageDest->pixels = (unsigned char *)malloc(row * bytes_per_row); +// + for (i=0;iheight ;i++) + #ifdef WIN32 + memcpy(&(imageDest->pixels[i*bytes_per_row]),&(pixels[bytes_per_row *(imageDest->height-i-1)]),bytes_per_row); + #else + bcopy(&(pixels[bytes_per_row *(imageDest->height-i-1)]),&(imageDest->pixels[i*bytes_per_row]),bytes_per_row); + #endif +// #else +// for (i=0;iheight ;i++) +// #ifdef WIN32 +// memcpy(&(imageDest->pixels[i*bytes_per_row]),&(pixels[i*bytes_per_row]),bytes_per_row); +// #else +// bcopy(&(pixels[i*bytes_per_row]),&(imageDest->pixels[i*bytes_per_row]),bytes_per_row); +// #endif +// +// #endif + free(pixels); + + fclose(fp); + return 1; +} + +int write_png(const char *file_name, unsigned char *image, int width, int height, int depth) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + int k; + png_bytep *row_pointers; + /* open the file */ + fp = fopen(file_name, "wb"); + if (fp == NULL) + return 0; + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fclose(fp); + return 0; + } + /* Allocate/initialize the image information data. REQUIRED */ + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + fclose(fp); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return 0; + } + /* Set error handling. REQUIRED if you aren't supplying your own + * error hadnling functions in the png_create_write_struct() call. + */ + if (setjmp(png_ptr->jmpbuf)) + { + /* If we get here, we had a problem writing the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return 0; + } + /* set up the output control if you are using standard C streams */ + png_init_io(png_ptr, fp); + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + */ + switch (depth) { + case 1: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY,\ + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + break; + case 2: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY_ALPHA,\ + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + break; + case 3: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,\ + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + break; + case 4: + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA,\ + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + break; + default: + printf("Profondeur de couleur non support? pour la sauvegarde en png.\n"); + } + + /* Write the file header information. REQUIRED */ + png_write_info(png_ptr, info_ptr); + /* The easiest way to write the image (you may have a different memory + * layout, however, so choose what fits your needs best). You need to + * use the first method if you aren't handling interlacing yourself. + */ + row_pointers= (png_bytep *)malloc(sizeof(png_bytep) *height); + for (k = 0; k < height; k++) + row_pointers[k] = image + k*width*depth; + /* write out the entire image data in one call */ + png_write_image(png_ptr, row_pointers); + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + /* clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + /* close the file */ + fclose(fp); + /* that's it */ + free (row_pointers); + return (1); +} + + +/*------------------------------------------------------------------*/ +/* fonction exportee par le module */ +#define MAX_STRING 2048 +Image chargeImage(const char *path) +{ + #ifdef WIN32 + char drive[MAX_STRING]; + char dir[MAX_STRING]; + char fname[MAX_STRING]; + char ext[MAX_STRING]; + #else + char ext[MAX_STRING]; + #endif + + Image newImage=(Image)malloc(sizeof(internalImageRepresentation)); + + #ifdef WIN32 + _splitpath( path, drive, dir, fname, ext ); + #else + strcpy(ext,strrchr(path,'.')); + #endif + + if ( (strcmp(ext,".png")==0) || (strcmp(ext,".PNG")==0) ) { + if (loadPng( newImage, path ) ) { + return (newImage); + } else { + return (NULL); + } + } + free (newImage); + return (NULL); +} +#undef MAX_STRING + +Image creeImage(unsigned char *pixels, int width, int height, int depth) +{ + Image newImage=(Image)malloc(sizeof(internalImageRepresentation)); + newImage->pixels=pixels; + newImage->width=width; + newImage->height=height; + newImage->depth=depth; + return (newImage); +} + +void detruireImage(Image *imageADetruire) +{ + free ((*imageADetruire)->pixels); + free (*imageADetruire); + *imageADetruire=NULL; +} + +void imageSauvePng(Image image, const char* path) +{ + + unsigned int i; + unsigned char *zap_image = (unsigned char*)malloc(image->width*image->height*image->depth*sizeof(unsigned char)); + + int bytes_per_row = image->width*image->depth; + for (i=0;iheight ;i++) + #ifdef WIN32 + memcpy(&(zap_image[i*bytes_per_row]),&(image->pixels[bytes_per_row*(image->height-i-1)]),bytes_per_row); + #else + bcopy(&(image->pixels[bytes_per_row*(image->height-i-1)]),&(zap_image[i*bytes_per_row]),bytes_per_row); + #endif + + if ( !write_png(path, zap_image, image->width,image->height,image->depth) ) + printf ("Probleme d'ecriture ... \n"); + + free (zap_image); +} + +unsigned char *imageGetPixels(Image image) +{ + return (image->pixels); +} + +int imageGetWidth(Image image) +{ + return (image->width); +} + +int imageGetHeight(Image image) +{ + return (image->height); +} + +int imageGetDepth(Image image) +{ + return (image->depth); +} + + + + + + \ No newline at end of file diff --git a/src/Image.h b/src/Image.h new file mode 100644 index 0000000..216ff3a --- /dev/null +++ b/src/Image.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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. * + ***************************************************************************/ +/*-------------------------------------------------------------------- + -- Introduction a OpenGL + -- Master 1 Informatique + -- UPS + -- + -- Mathias Paulin 2006 + -- + -------------------------------------------------------------------*/ +#ifndef __ImageTexture__ +#define __ImageTexture__ + +/** \addtogroup Image + + \bug A voir +*/ +/*@{*/ + +/** Type opaque Image. +*/ +typedef struct _image *Image; + +/** Cr?ation d'une image. + L'image cr??e sera charg?e a partir du fichier dont + le nom est pass? en param?tre. Les formats support?s sont : + - JPEG (attention, compr?ssion avec perte). + - PNG (conseill?, le plus g?n?ral). + \param path chemin d'acc?s ? l'image. + \return l'image charg?e, NULL si erreur. +*/ +Image chargeImage(const char *path); + +/** Cr?ation d'une image. + Cr?ation de la structure Image a partir d'un tableau de width*height pixels, + chaque pixel etant cod? par depth unsigned char. + Le tableau pixels contient l'image rang?e par ligne . Le pixel (i,j) + comence donc ? l'adresse pixels + (i*width*depth) + j*depth . + + \attention Si la taille de pixels n'est pas width*height*depth, il y aura + segmentation fault, voire pire!!! + + \param pixels tableau des pixels. + \param width largeur de l'image. + \param height hauteur de l'image. + \param depth profondeur de l'image. + +*/ +Image creeImage(unsigned char *pixels, int width, int height, int depth); + +/** Sauvegarde de l'image au format png. + \param image image ? sauver. + \param path nom du fichier destination. +*/ +void imageSauvePng(Image image, const char* path); + +/** Lib?ration de la structure image. +*/ +void detruireImage(Image *imageADetruire); + +/** Acces au tableau de pixels. +*/ +unsigned char *imageGetPixels(Image image); + +/** Acces ? la largeur de l'image. +*/ +int imageGetWidth(Image image); + +/** Acces ? la hauteur de l'image. +*/ +int imageGetHeight(Image image); + +/** Acces ? la profondeur de l'image. +*/ +int imageGetDepth(Image image); + +/** @} end */ + + +#endif diff --git a/src/Light.cpp b/src/Light.cpp new file mode 100644 index 0000000..db8bea5 --- /dev/null +++ b/src/Light.cpp @@ -0,0 +1,152 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Light.h" +#include "Material.h" +//#include "OpenGL.h" +#include + +//-------------------------------------------------------------------------------- +Light::Light(LightType lt,const QString& name) + : Entity(name), mColor(Color::WHITE), mGlLightId(0), mType(lt), mAperture(45.), mExponent(10.) +{ + setPosition(Vector3(1.,1.,1.)); + setDirection(Vector3(-1.,-1.,-1.)); + mpMaterial = new Material(); + mpMaterial->setLighted(false); + mpMaterial->setBaseColor(mColor,0.5); +} +Light::~Light() +{ + delete mpMaterial; +} +//-------------------------------------------------------------------------------- +Light::LightType Light::getType(void) const +{ + return mType; +} +//-------------------------------------------------------------------------------- +void Light::activate(int num) +{ + float v4[4]; + + mGlLightId = GL_LIGHT0 + num; + + glLightfv(mGlLightId, GL_AMBIENT, Color::BLACK); + glLightfv(mGlLightId, GL_DIFFUSE, mColor); + glLightfv(mGlLightId, GL_SPECULAR, mColor); + + if(mType != LT_DIRECTIONAL) + { + Vector3 pos = getPosition(); + v4[0] = pos.x; v4[1] = pos.y; v4[2] = pos.z; + v4[3] = 1.; + } + else + { + Vector3 dir = getDirection(); + v4[0] = dir.x; v4[1] = dir.y; v4[2] = dir.z; + v4[3] = 0.; + } + glLightfv(mGlLightId, GL_POSITION, v4); + + if(mType == LT_SPOT) + { + Vector3 dir = getDirection(); + v4[0] = dir.x; v4[1] = dir.y; v4[2] = dir.z; + v4[3] = 1.; + glLightfv(mGlLightId, GL_SPOT_DIRECTION, v4); + glLightf(mGlLightId, GL_SPOT_CUTOFF, mAperture); + glLightf(mGlLightId, GL_SPOT_EXPONENT, mExponent); + } + else + { + glLightf(mGlLightId, GL_SPOT_CUTOFF, 180.); + } + glEnable(mGlLightId); +} +//-------------------------------------------------------------------------------- +void Light::release(void) +{ + glDisable(mGlLightId); + glLightfv(mGlLightId, GL_AMBIENT, Color::BLACK); + glLightfv(mGlLightId, GL_DIFFUSE, Color::BLACK); + glLightfv(mGlLightId, GL_SPECULAR, Color::BLACK); +} +//-------------------------------------------------------------------------------- +void Light::setPosition(const Vector3& pos) +{ + mTransform.setPosition(pos); +} +const Vector3& Light::getPosition(void) const +{ + return mTransform.getPosition(); +} +//-------------------------------------------------------------------------------- +void Light::setDirection(const Vector3& _dir) +{ + Vector3 dir = _dir; + dir.normalise(); + Vector3 rotAxes = Vector3::UNIT_Z.crossProduct(dir); + float rotAngle = acos(Vector3::UNIT_Z.dotProduct(dir)); + mTransform.setOrientation(rotAngle, rotAxes.x, rotAxes.y, rotAxes.z); +} +Vector3 Light::getDirection(void) const +{ + Vector3 x, y, z; + mTransform.getOrientation().ToAxes(x, y, z); + return z; +} +//-------------------------------------------------------------------------------- +void Light::setColor(const Color& c) +{ + mColor = c; + mpMaterial->setBaseColor(mColor,0.5); +} +//-------------------------------------------------------------------------------- +float Light::getAperture(void) const +{ + return mAperture; +} +void Light::setAperture(float a) +{ + if(a<90.) + mAperture = a; +} +float Light::getExponent(void) const +{ + return mExponent; +} +void Light::setExponent(float e) +{ + mExponent = e; +} +//-------------------------------------------------------------------------------- +void Light::drawGeometry(void) +{ +} + +Vector3 Light::getCenterM(void) +{ + Vector3 center; + center.x = 0.; + center.y = 0.; + center.z = 0.; + return center; +} + +std::vector Light::getVertexArray(){ + std::vector vect; + return vect; +} + + +void Light::deleteVBO(){} + +void Light::afficheInfoM(int split){} + +void Light::fillDensity(int coverage, Density *pDensity){} diff --git a/src/Light.h b/src/Light.h new file mode 100644 index 0000000..49341b2 --- /dev/null +++ b/src/Light.h @@ -0,0 +1,84 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Light_h_ +#define _Light_h_ + +#include +#include "Vector3.h" +#include "Material.h" +#include "Entity.h" + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Light : public Entity +{ +public: + enum LightType {LT_POINT, LT_DIRECTIONAL, LT_SPOT}; + + Light(LightType lt, const QString& name = ""); + + ~Light(); + + LightType getType(void) const; + + /** Met à  jour les états OpenGL et active la source lumineuse. + Le numéro de la source lumineuse OpenGL utilisé est GL_LIGHTnum, cà d GL_LIGHT0 + num. + */ + void activate(int num); + + /** Désactive la source lumimeuse. + */ + void release(void); + + /** Position de la source lumineuse. + Ignorée pour une source directionnelle. + */ + void setPosition(const Vector3& pos); + const Vector3& getPosition(void) const; + + /** Direction de la source lumineuse. + Ignorée pour une source ponctuelle. + */ + void setDirection(const Vector3& pos); + Vector3 getDirection(void) const; + + /** Couleur de la source lumineuse + */ + void setColor(const Color& c); + + /** Angle d'ouverture du spot. + */ + float getAperture(void) const; + void setAperture(float a); + + /** Atténuation du faisceau. + */ + float getExponent(void) const; + void setExponent(float e); + +protected: + + virtual void drawGeometry(void); + virtual Vector3 getCenterM(void); + virtual std::vector getVertexArray(); + virtual void deleteVBO(); + virtual void afficheInfoM(int split); + virtual void fillDensity(int coverage, Density *pDensity); + Color mColor; + int mGlLightId; + LightType mType; + float mAperture; + float mExponent; +}; + +#endif diff --git a/src/Material.cpp b/src/Material.cpp new file mode 100644 index 0000000..785ec7a --- /dev/null +++ b/src/Material.cpp @@ -0,0 +1,184 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Material.h" +#include "TextureLayer.h" + + +bool Material::configEnableShaders = false; + +Material Material::Default; + +//-------------------------------------------------------------------------------- +Material::Material(void) + : mColor(0.8,0.8,0.8), mAmbient(0.3,0.3,0.3), mDiffuse(0.5,0.5,0.5), + mSpecular(0.8,0.8,0.8), mShininess(10), + mActiveBlending(false), mBlendSrcFunc(GL_ONE), mBlendDstFunc(GL_ZERO), + mAlphaRejection(false), mAlphaRejectionValue(1.), mIsLighted(true) +{ +} +//-------------------------------------------------------------------------------- +void Material::activate(bool alphaOnly /*= false*/) +{ + if(!alphaOnly) + { + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mAmbient); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mDiffuse); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mSpecular); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mShininess); + + // si l'éclairage n'est pas activé + glColor4fv(mColor); + + if(!mIsLighted) + { + mPreviousLightingState = glIsEnabled(GL_LIGHTING); + glDisable(GL_LIGHTING); + } + + if(mActiveBlending) + { + glEnable(GL_BLEND); + glBlendFunc(mBlendSrcFunc, mBlendDstFunc); + } + } + + if(!alphaOnly || mAlphaRejection) + { + /*******************************************************************/ + /* Début code à  faire/completer par l'étudiant */ + /* Texture */ + /*******************************************************************/ + + // à  faire : activer chaque texture dans une unité de texture différente + GLuint unit = 0; + for(TextureLayers::iterator it = mTextureLayers.begin() ; + it!=mTextureLayers.end() ; ++unit, ++it) + { + glActiveTexture(GL_TEXTURE0 + unit); + (*it)->activate(); + } + glActiveTexture(GL_TEXTURE0); + + + /*******************************************************************/ + /* Fin code à  faire/completer par l'étudiant */ + /* Texture */ + /*******************************************************************/ + } + + if(mAlphaRejection) + { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, mAlphaRejectionValue); + } +} +//-------------------------------------------------------------------------------- +void Material::release(bool alphaOnly /*= false*/) +{ + if(!alphaOnly) + { + if(mActiveBlending) + { + glDisable(GL_BLEND); + } + if(!mIsLighted && mPreviousLightingState) + { + glEnable(GL_LIGHTING); + } + } + + if(!alphaOnly || mAlphaRejection) + { + /*******************************************************************/ + /* Début code à  faire/completer par l'étudiant */ + /* Texture */ + /*******************************************************************/ + + // à  faire : désactiver chaque texture de leur unité respective + GLuint unit = GL_TEXTURE0; + for(TextureLayers::iterator it = mTextureLayers.begin() ; + it!=mTextureLayers.end() ; ++unit, ++it) + { + glActiveTexture(unit); + (*it)->release(); + } + glActiveTexture(GL_TEXTURE0); + + /*******************************************************************/ + /* Fin code à  faire/completer par l'étudiant */ + /* Texture */ + /*******************************************************************/ + } + + if(mAlphaRejection) + { + glDisable(GL_ALPHA_TEST); + } +} +//-------------------------------------------------------------------------------- +void Material::setBaseColor(const Color& c, float coeffAmbient) +{ + mAmbient = c * coeffAmbient * 2.0; + + mDiffuse = c * (1.-coeffAmbient); + + mColor = c; + + // l'alpha du sommet éclairé est égale à  l'alpha de la composante diffuse + mDiffuse.a = c.a; +} + +void Material::setSpecular(const Color& c, float shininess) +{ + mSpecular = c; + // shininess entre 0 et 1 + // pour OpenGL : entre 0 et 128 + mShininess = shininess * 128; +} +//-------------------------------------------------------------------------------- +void Material::setBlendFunc(GLenum src, GLenum dst) +{ + mBlendSrcFunc = src; + mBlendDstFunc = dst; + mActiveBlending = (src!=GL_ONE) || (dst!=GL_ZERO); +} +//-------------------------------------------------------------------------------- +void Material::setAlphaRejection(float value) +{ + mAlphaRejectionValue = value; + mAlphaRejection = (value>0.); +} + +bool Material::hasAlphaRejection(void) const +{ + return mAlphaRejection; +} +//-------------------------------------------------------------------------------- +void Material::setLighted(bool on) +{ + mIsLighted = on; +} +bool Material::isLighted(void) const +{ + return mIsLighted; +} +//-------------------------------------------------------------------------------- +void Material::pushTextureLayer(TextureLayer* pTex) +{ + mTextureLayers.push_back(pTex); +} +//-------------------------------------------------------------------------------- +int Material::getNumberOfLayers(void) +{ + return mTextureLayers.size(); +} +//-------------------------------------------------------------------------------- +void Material::popTextureLayer() +{ + mTextureLayers.pop_back(); +} diff --git a/src/Material.h b/src/Material.h new file mode 100644 index 0000000..c33cd36 --- /dev/null +++ b/src/Material.h @@ -0,0 +1,125 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Material_h_ +#define _Material_h_ + +#include +#include +#include "OpenGL.h" + +#include "Color.h" + + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class TextureLayer; + +class Material +{ +public: + + Material(void); + + /** Active l'ensemble du materiau, cà d mà j des états OpenGL: + - materiaux + - blending + - test alpha + \note à  completer par l'étudiant (texture) + */ + void activate(bool alphaOnly = false); + + /** Désactive le blending, le test alpha + \note à  completer par l'étudiant (texture) + */ + void release(bool alphaOnly = false); + + + /** + \param c couleur de l'objet + \param coeffAmbient coefficient d'ambiant entre 0 et 1 + */ + void setBaseColor(const Color& c, float coeffAmbient); + + /** + \param c couleur des reflets spéculaires + \param shininess coefficient de brillance entre 0 et 1 + */ + void setSpecular(const Color& c, float shininess); + + /** Spécifie les facteurs de sources et de destination du blending. + Par defaut le blending est désactivé. + Utiliser setBlendFunc(GL_ONE,GL_ZERO) pour désactiver le blending dans le matériau + */ + void setBlendFunc(GLenum src, GLenum dst); + + /** Spécifie la valeur minimal de l'alpha des fragments. + Utiliser setAlphaRejection(0) pour désactiver le test sur l'alpha + */ + void setAlphaRejection(float value); + bool hasAlphaRejection(void) const; + + /** Spécifie si le matériau peut être éclairé ou non. + \note Ceci est utile pour les objets n'ayant pas de surface ou de normales. + */ + void setLighted(bool on); + bool isLighted(void) const; + + + /** Ajoute une couche de texture + */ + void pushTextureLayer(TextureLayer* pTex); + /** Retire une couche de texture + */ + void popTextureLayer(); + /** Nombre de couches de texture du materiau + */ + int getNumberOfLayers(void); + +public: + + /** Materiau par defaut. + */ + static Material Default; + + //-------------------------------------------------------------------------------- + // configuration globale + + /** active/désactive l'utilisation des shaders + */ + static bool configEnableShaders; + //-------------------------------------------------------------------------------- + +protected: + + Color mColor; + Color mAmbient; + Color mDiffuse; + Color mSpecular; + float mShininess; + + bool mActiveBlending; + GLenum mBlendSrcFunc; + GLenum mBlendDstFunc; + + bool mAlphaRejection; + float mAlphaRejectionValue; + + bool mIsLighted; + bool mPreviousLightingState; + + typedef std::vector TextureLayers; + /// Stocke la liste des textures associées au matériau. + TextureLayers mTextureLayers; +}; + +#endif diff --git a/src/Matrix3.cpp b/src/Matrix3.cpp new file mode 100644 index 0000000..b1eee61 --- /dev/null +++ b/src/Matrix3.cpp @@ -0,0 +1,1557 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +#include "Matrix3.h" + +#include +#include + +// Adapted from Matrix math by Wild Magic http://www.magic-software.com + + +const float Matrix3::EPSILON = 1e-06; +const Matrix3 Matrix3::ZERO(0,0,0,0,0,0,0,0,0); +const Matrix3 Matrix3::IDENTITY(1,0,0,0,1,0,0,0,1); +const float Matrix3::ms_fSvdEpsilon = 1e-04; +const int Matrix3::ms_iSvdMaxIterations = 32; + +//----------------------------------------------------------------------- +Matrix3::Matrix3 () +{ + // For efficiency reasons, do not initialize matrix. +} +//----------------------------------------------------------------------- +Matrix3::Matrix3 (const float aafEntry[3][3]) +{ + memcpy(m,aafEntry,9*sizeof(float)); +} +//----------------------------------------------------------------------- +Matrix3::Matrix3 (const Matrix3& rkMatrix) +{ + memcpy(m,rkMatrix.m,9*sizeof(float)); +} +//----------------------------------------------------------------------- +Matrix3::Matrix3 (float fEntry00, float fEntry01, float fEntry02, + float fEntry10, float fEntry11, float fEntry12, float fEntry20, + float fEntry21, float fEntry22) +{ + m[0][0] = fEntry00; + m[0][1] = fEntry01; + m[0][2] = fEntry02; + m[1][0] = fEntry10; + m[1][1] = fEntry11; + m[1][2] = fEntry12; + m[2][0] = fEntry20; + m[2][1] = fEntry21; + m[2][2] = fEntry22; +} +//----------------------------------------------------------------------- +float* Matrix3::operator[] (int iRow) const +{ + return (float*)m[iRow]; +} +//----------------------------------------------------------------------- +Matrix3::operator float* () +{ + return (float*)m[0]; +} +//----------------------------------------------------------------------- +Vector3 Matrix3::GetColumn (int iCol) const +{ + assert( 0 <= iCol && iCol < 3 ); + return Vector3(m[0][iCol],m[1][iCol], + m[2][iCol]); +} +//----------------------------------------------------------------------- +void Matrix3::SetColumn(int iCol, const Vector3& vec) +{ + assert( 0 <= iCol && iCol < 3 ); + m[0][iCol] = vec.x; + m[1][iCol] = vec.y; + m[2][iCol] = vec.z; + +} +//----------------------------------------------------------------------- +void Matrix3::FromAxes(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis) +{ + SetColumn(0,xAxis); + SetColumn(1,yAxis); + SetColumn(2,zAxis); + +} + +//----------------------------------------------------------------------- +Matrix3& Matrix3::operator= (const Matrix3& rkMatrix) +{ + memcpy(m,rkMatrix.m,9*sizeof(float)); + return *this; +} +//----------------------------------------------------------------------- +bool Matrix3::operator== (const Matrix3& rkMatrix) const +{ + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + { + if ( m[iRow][iCol] != rkMatrix.m[iRow][iCol] ) + return false; + } + } + + return true; +} +//----------------------------------------------------------------------- +bool Matrix3::operator!= (const Matrix3& rkMatrix) const +{ + return !operator==(rkMatrix); +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::operator+ (const Matrix3& rkMatrix) const +{ + Matrix3 kSum; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + { + kSum.m[iRow][iCol] = m[iRow][iCol] + + rkMatrix.m[iRow][iCol]; + } + } + return kSum; +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::operator- (const Matrix3& rkMatrix) const +{ + Matrix3 kDiff; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + { + kDiff.m[iRow][iCol] = m[iRow][iCol] - + rkMatrix.m[iRow][iCol]; + } + } + return kDiff; +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::operator* (const Matrix3& rkMatrix) const +{ + Matrix3 kProd; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + { + kProd.m[iRow][iCol] = + m[iRow][0]*rkMatrix.m[0][iCol] + + m[iRow][1]*rkMatrix.m[1][iCol] + + m[iRow][2]*rkMatrix.m[2][iCol]; + } + } + return kProd; +} +//----------------------------------------------------------------------- +Vector3 Matrix3::operator* (const Vector3& rkPoint) const +{ + Vector3 kProd; + for (int iRow = 0; iRow < 3; iRow++) + { + kProd[iRow] = + m[iRow][0]*rkPoint[0] + + m[iRow][1]*rkPoint[1] + + m[iRow][2]*rkPoint[2]; + } + return kProd; +} +//----------------------------------------------------------------------- +Vector3 operator* (const Vector3& rkPoint, const Matrix3& rkMatrix) +{ + Vector3 kProd; + for (int iRow = 0; iRow < 3; iRow++) + { + kProd[iRow] = + rkPoint[0]*rkMatrix.m[0][iRow] + + rkPoint[1]*rkMatrix.m[1][iRow] + + rkPoint[2]*rkMatrix.m[2][iRow]; + } + return kProd; +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::operator- () const +{ + Matrix3 kNeg; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + kNeg[iRow][iCol] = -m[iRow][iCol]; + } + return kNeg; +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::operator* (float fScalar) const +{ + Matrix3 kProd; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + kProd[iRow][iCol] = fScalar*m[iRow][iCol]; + } + return kProd; +} +//----------------------------------------------------------------------- +Matrix3 operator* (float fScalar, const Matrix3& rkMatrix) +{ + Matrix3 kProd; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + kProd[iRow][iCol] = fScalar*rkMatrix.m[iRow][iCol]; + } + return kProd; +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::Transpose () const +{ + Matrix3 kTranspose; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + kTranspose[iRow][iCol] = m[iCol][iRow]; + } + return kTranspose; +} +//----------------------------------------------------------------------- +bool Matrix3::Inverse (Matrix3& rkInverse, float fTolerance) const +{ + // Invert a 3x3 using cofactors. This is about 8 times faster than + // the Numerical Recipes code which uses Gaussian elimination. + + rkInverse[0][0] = m[1][1]*m[2][2] - + m[1][2]*m[2][1]; + rkInverse[0][1] = m[0][2]*m[2][1] - + m[0][1]*m[2][2]; + rkInverse[0][2] = m[0][1]*m[1][2] - + m[0][2]*m[1][1]; + rkInverse[1][0] = m[1][2]*m[2][0] - + m[1][0]*m[2][2]; + rkInverse[1][1] = m[0][0]*m[2][2] - + m[0][2]*m[2][0]; + rkInverse[1][2] = m[0][2]*m[1][0] - + m[0][0]*m[1][2]; + rkInverse[2][0] = m[1][0]*m[2][1] - + m[1][1]*m[2][0]; + rkInverse[2][1] = m[0][1]*m[2][0] - + m[0][0]*m[2][1]; + rkInverse[2][2] = m[0][0]*m[1][1] - + m[0][1]*m[1][0]; + + float fDet = + m[0][0]*rkInverse[0][0] + + m[0][1]*rkInverse[1][0]+ + m[0][2]*rkInverse[2][0]; + + if ( fabs(fDet) <= fTolerance ) + return false; + + float fInvDet = 1.0/fDet; + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + rkInverse[iRow][iCol] *= fInvDet; + } + + return true; +} +//----------------------------------------------------------------------- +Matrix3 Matrix3::Inverse (float fTolerance) const +{ + Matrix3 kInverse = Matrix3::ZERO; + Inverse(kInverse,fTolerance); + return kInverse; +} +//----------------------------------------------------------------------- +float Matrix3::Determinant () const +{ + float fCofactor00 = m[1][1]*m[2][2] - + m[1][2]*m[2][1]; + float fCofactor10 = m[1][2]*m[2][0] - + m[1][0]*m[2][2]; + float fCofactor20 = m[1][0]*m[2][1] - + m[1][1]*m[2][0]; + + float fDet = + m[0][0]*fCofactor00 + + m[0][1]*fCofactor10 + + m[0][2]*fCofactor20; + + return fDet; +} +//----------------------------------------------------------------------- +void Matrix3::Bidiagonalize (Matrix3& kA, Matrix3& kL, + Matrix3& kR) +{ + float afV[3], afW[3]; + float fLength, fSign, fT1, fInvT1, fT2; + bool bIdentity; + + // map first column to (*,0,0) + fLength = sqrt(kA[0][0]*kA[0][0] + kA[1][0]*kA[1][0] + + kA[2][0]*kA[2][0]); + if ( fLength > 0.0 ) + { + fSign = (kA[0][0] > 0.0 ? 1.0 : -1.0); + fT1 = kA[0][0] + fSign*fLength; + fInvT1 = 1.0/fT1; + afV[1] = kA[1][0]*fInvT1; + afV[2] = kA[2][0]*fInvT1; + + fT2 = -2.0/(1.0+afV[1]*afV[1]+afV[2]*afV[2]); + afW[0] = fT2*(kA[0][0]+kA[1][0]*afV[1]+kA[2][0]*afV[2]); + afW[1] = fT2*(kA[0][1]+kA[1][1]*afV[1]+kA[2][1]*afV[2]); + afW[2] = fT2*(kA[0][2]+kA[1][2]*afV[1]+kA[2][2]*afV[2]); + kA[0][0] += afW[0]; + kA[0][1] += afW[1]; + kA[0][2] += afW[2]; + kA[1][1] += afV[1]*afW[1]; + kA[1][2] += afV[1]*afW[2]; + kA[2][1] += afV[2]*afW[1]; + kA[2][2] += afV[2]*afW[2]; + + kL[0][0] = 1.0+fT2; + kL[0][1] = kL[1][0] = fT2*afV[1]; + kL[0][2] = kL[2][0] = fT2*afV[2]; + kL[1][1] = 1.0+fT2*afV[1]*afV[1]; + kL[1][2] = kL[2][1] = fT2*afV[1]*afV[2]; + kL[2][2] = 1.0+fT2*afV[2]*afV[2]; + bIdentity = false; + } + else + { + kL = Matrix3::IDENTITY; + bIdentity = true; + } + + // map first row to (*,*,0) + fLength = sqrt(kA[0][1]*kA[0][1]+kA[0][2]*kA[0][2]); + if ( fLength > 0.0 ) + { + fSign = (kA[0][1] > 0.0 ? 1.0 : -1.0); + fT1 = kA[0][1] + fSign*fLength; + afV[2] = kA[0][2]/fT1; + + fT2 = -2.0/(1.0+afV[2]*afV[2]); + afW[0] = fT2*(kA[0][1]+kA[0][2]*afV[2]); + afW[1] = fT2*(kA[1][1]+kA[1][2]*afV[2]); + afW[2] = fT2*(kA[2][1]+kA[2][2]*afV[2]); + kA[0][1] += afW[0]; + kA[1][1] += afW[1]; + kA[1][2] += afW[1]*afV[2]; + kA[2][1] += afW[2]; + kA[2][2] += afW[2]*afV[2]; + + kR[0][0] = 1.0; + kR[0][1] = kR[1][0] = 0.0; + kR[0][2] = kR[2][0] = 0.0; + kR[1][1] = 1.0+fT2; + kR[1][2] = kR[2][1] = fT2*afV[2]; + kR[2][2] = 1.0+fT2*afV[2]*afV[2]; + } + else + { + kR = Matrix3::IDENTITY; + } + + // map second column to (*,*,0) + fLength = sqrt(kA[1][1]*kA[1][1]+kA[2][1]*kA[2][1]); + if ( fLength > 0.0 ) + { + fSign = (kA[1][1] > 0.0 ? 1.0 : -1.0); + fT1 = kA[1][1] + fSign*fLength; + afV[2] = kA[2][1]/fT1; + + fT2 = -2.0/(1.0+afV[2]*afV[2]); + afW[1] = fT2*(kA[1][1]+kA[2][1]*afV[2]); + afW[2] = fT2*(kA[1][2]+kA[2][2]*afV[2]); + kA[1][1] += afW[1]; + kA[1][2] += afW[2]; + kA[2][2] += afV[2]*afW[2]; + + float fA = 1.0+fT2; + float fB = fT2*afV[2]; + float fC = 1.0+fB*afV[2]; + + if ( bIdentity ) + { + kL[0][0] = 1.0; + kL[0][1] = kL[1][0] = 0.0; + kL[0][2] = kL[2][0] = 0.0; + kL[1][1] = fA; + kL[1][2] = kL[2][1] = fB; + kL[2][2] = fC; + } + else + { + for (int iRow = 0; iRow < 3; iRow++) + { + float fTmp0 = kL[iRow][1]; + float fTmp1 = kL[iRow][2]; + kL[iRow][1] = fA*fTmp0+fB*fTmp1; + kL[iRow][2] = fB*fTmp0+fC*fTmp1; + } + } + } +} +//----------------------------------------------------------------------- +void Matrix3::GolubKahanStep (Matrix3& kA, Matrix3& kL, + Matrix3& kR) +{ + float fT11 = kA[0][1]*kA[0][1]+kA[1][1]*kA[1][1]; + float fT22 = kA[1][2]*kA[1][2]+kA[2][2]*kA[2][2]; + float fT12 = kA[1][1]*kA[1][2]; + float fTrace = fT11+fT22; + float fDiff = fT11-fT22; + float fDiscr = sqrt(fDiff*fDiff+4.0*fT12*fT12); + float fRoot1 = 0.5*(fTrace+fDiscr); + float fRoot2 = 0.5*(fTrace-fDiscr); + + // adjust right + float fY = kA[0][0] - (fabs(fRoot1-fT22) <= + fabs(fRoot2-fT22) ? fRoot1 : fRoot2); + float fZ = kA[0][1]; + float fInvLength = 1.0/sqrt(fY*fY+fZ*fZ); + float fSin = fZ*fInvLength; + float fCos = -fY*fInvLength; + + float fTmp0 = kA[0][0]; + float fTmp1 = kA[0][1]; + kA[0][0] = fCos*fTmp0-fSin*fTmp1; + kA[0][1] = fSin*fTmp0+fCos*fTmp1; + kA[1][0] = -fSin*kA[1][1]; + kA[1][1] *= fCos; + + int iRow; + for (iRow = 0; iRow < 3; iRow++) + { + fTmp0 = kR[0][iRow]; + fTmp1 = kR[1][iRow]; + kR[0][iRow] = fCos*fTmp0-fSin*fTmp1; + kR[1][iRow] = fSin*fTmp0+fCos*fTmp1; + } + + // adjust left + fY = kA[0][0]; + fZ = kA[1][0]; + fInvLength = 1.0/sqrt(fY*fY+fZ*fZ); + fSin = fZ*fInvLength; + fCos = -fY*fInvLength; + + kA[0][0] = fCos*kA[0][0]-fSin*kA[1][0]; + fTmp0 = kA[0][1]; + fTmp1 = kA[1][1]; + kA[0][1] = fCos*fTmp0-fSin*fTmp1; + kA[1][1] = fSin*fTmp0+fCos*fTmp1; + kA[0][2] = -fSin*kA[1][2]; + kA[1][2] *= fCos; + + int iCol; + for (iCol = 0; iCol < 3; iCol++) + { + fTmp0 = kL[iCol][0]; + fTmp1 = kL[iCol][1]; + kL[iCol][0] = fCos*fTmp0-fSin*fTmp1; + kL[iCol][1] = fSin*fTmp0+fCos*fTmp1; + } + + // adjust right + fY = kA[0][1]; + fZ = kA[0][2]; + fInvLength = 1.0/sqrt(fY*fY+fZ*fZ); + fSin = fZ*fInvLength; + fCos = -fY*fInvLength; + + kA[0][1] = fCos*kA[0][1]-fSin*kA[0][2]; + fTmp0 = kA[1][1]; + fTmp1 = kA[1][2]; + kA[1][1] = fCos*fTmp0-fSin*fTmp1; + kA[1][2] = fSin*fTmp0+fCos*fTmp1; + kA[2][1] = -fSin*kA[2][2]; + kA[2][2] *= fCos; + + for (iRow = 0; iRow < 3; iRow++) + { + fTmp0 = kR[1][iRow]; + fTmp1 = kR[2][iRow]; + kR[1][iRow] = fCos*fTmp0-fSin*fTmp1; + kR[2][iRow] = fSin*fTmp0+fCos*fTmp1; + } + + // adjust left + fY = kA[1][1]; + fZ = kA[2][1]; + fInvLength = 1.0/sqrt(fY*fY+fZ*fZ); + fSin = fZ*fInvLength; + fCos = -fY*fInvLength; + + kA[1][1] = fCos*kA[1][1]-fSin*kA[2][1]; + fTmp0 = kA[1][2]; + fTmp1 = kA[2][2]; + kA[1][2] = fCos*fTmp0-fSin*fTmp1; + kA[2][2] = fSin*fTmp0+fCos*fTmp1; + + for (iCol = 0; iCol < 3; iCol++) + { + fTmp0 = kL[iCol][1]; + fTmp1 = kL[iCol][2]; + kL[iCol][1] = fCos*fTmp0-fSin*fTmp1; + kL[iCol][2] = fSin*fTmp0+fCos*fTmp1; + } +} +//----------------------------------------------------------------------- +void Matrix3::SingularValueDecomposition (Matrix3& kL, Vector3& kS, + Matrix3& kR) const +{ + // temas: currently unused + //const int iMax = 16; + int iRow, iCol; + + Matrix3 kA = *this; + Bidiagonalize(kA,kL,kR); + + for (int i = 0; i < ms_iSvdMaxIterations; i++) + { + float fTmp, fTmp0, fTmp1; + float fSin0, fCos0, fTan0; + float fSin1, fCos1, fTan1; + + bool bTest1 = (fabs(kA[0][1]) <= + ms_fSvdEpsilon*(fabs(kA[0][0])+fabs(kA[1][1]))); + bool bTest2 = (fabs(kA[1][2]) <= + ms_fSvdEpsilon*(fabs(kA[1][1])+fabs(kA[2][2]))); + if ( bTest1 ) + { + if ( bTest2 ) + { + kS[0] = kA[0][0]; + kS[1] = kA[1][1]; + kS[2] = kA[2][2]; + break; + } + else + { + // 2x2 closed form factorization + fTmp = (kA[1][1]*kA[1][1] - kA[2][2]*kA[2][2] + + kA[1][2]*kA[1][2])/(kA[1][2]*kA[2][2]); + fTan0 = 0.5*(fTmp+sqrt(fTmp*fTmp + 4.0)); + fCos0 = 1.0/sqrt(1.0+fTan0*fTan0); + fSin0 = fTan0*fCos0; + + for (iCol = 0; iCol < 3; iCol++) + { + fTmp0 = kL[iCol][1]; + fTmp1 = kL[iCol][2]; + kL[iCol][1] = fCos0*fTmp0-fSin0*fTmp1; + kL[iCol][2] = fSin0*fTmp0+fCos0*fTmp1; + } + + fTan1 = (kA[1][2]-kA[2][2]*fTan0)/kA[1][1]; + fCos1 = 1.0/sqrt(1.0+fTan1*fTan1); + fSin1 = -fTan1*fCos1; + + for (iRow = 0; iRow < 3; iRow++) + { + fTmp0 = kR[1][iRow]; + fTmp1 = kR[2][iRow]; + kR[1][iRow] = fCos1*fTmp0-fSin1*fTmp1; + kR[2][iRow] = fSin1*fTmp0+fCos1*fTmp1; + } + + kS[0] = kA[0][0]; + kS[1] = fCos0*fCos1*kA[1][1] - + fSin1*(fCos0*kA[1][2]-fSin0*kA[2][2]); + kS[2] = fSin0*fSin1*kA[1][1] + + fCos1*(fSin0*kA[1][2]+fCos0*kA[2][2]); + break; + } + } + else + { + if ( bTest2 ) + { + // 2x2 closed form factorization + fTmp = (kA[0][0]*kA[0][0] + kA[1][1]*kA[1][1] - + kA[0][1]*kA[0][1])/(kA[0][1]*kA[1][1]); + fTan0 = 0.5*(-fTmp+sqrt(fTmp*fTmp + 4.0)); + fCos0 = 1.0/sqrt(1.0+fTan0*fTan0); + fSin0 = fTan0*fCos0; + + for (iCol = 0; iCol < 3; iCol++) + { + fTmp0 = kL[iCol][0]; + fTmp1 = kL[iCol][1]; + kL[iCol][0] = fCos0*fTmp0-fSin0*fTmp1; + kL[iCol][1] = fSin0*fTmp0+fCos0*fTmp1; + } + + fTan1 = (kA[0][1]-kA[1][1]*fTan0)/kA[0][0]; + fCos1 = 1.0/sqrt(1.0+fTan1*fTan1); + fSin1 = -fTan1*fCos1; + + for (iRow = 0; iRow < 3; iRow++) + { + fTmp0 = kR[0][iRow]; + fTmp1 = kR[1][iRow]; + kR[0][iRow] = fCos1*fTmp0-fSin1*fTmp1; + kR[1][iRow] = fSin1*fTmp0+fCos1*fTmp1; + } + + kS[0] = fCos0*fCos1*kA[0][0] - + fSin1*(fCos0*kA[0][1]-fSin0*kA[1][1]); + kS[1] = fSin0*fSin1*kA[0][0] + + fCos1*(fSin0*kA[0][1]+fCos0*kA[1][1]); + kS[2] = kA[2][2]; + break; + } + else + { + GolubKahanStep(kA,kL,kR); + } + } + } + + // positize diagonal + for (iRow = 0; iRow < 3; iRow++) + { + if ( kS[iRow] < 0.0 ) + { + kS[iRow] = -kS[iRow]; + for (iCol = 0; iCol < 3; iCol++) + kR[iRow][iCol] = -kR[iRow][iCol]; + } + } +} +//----------------------------------------------------------------------- +void Matrix3::SingularValueComposition (const Matrix3& kL, + const Vector3& kS, const Matrix3& kR) +{ + int iRow, iCol; + Matrix3 kTmp; + + // product S*R + for (iRow = 0; iRow < 3; iRow++) + { + for (iCol = 0; iCol < 3; iCol++) + kTmp[iRow][iCol] = kS[iRow]*kR[iRow][iCol]; + } + + // product L*S*R + for (iRow = 0; iRow < 3; iRow++) + { + for (iCol = 0; iCol < 3; iCol++) + { + m[iRow][iCol] = 0.0; + for (int iMid = 0; iMid < 3; iMid++) + m[iRow][iCol] += kL[iRow][iMid]*kTmp[iMid][iCol]; + } + } +} +//----------------------------------------------------------------------- +void Matrix3::Orthonormalize () +{ + // Algorithm uses Gram-Schmidt orthogonalization. If 'this' matrix is + // M = [m0|m1|m2], then orthonormal output matrix is Q = [q0|q1|q2], + // + // q0 = m0/|m0| + // q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0| + // q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1| + // + // where |V| indicates length of vector V and A*B indicates dot + // product of vectors A and B. + + // compute q0 + float fInvLength = 1.0/sqrt(m[0][0]*m[0][0] + + m[1][0]*m[1][0] + + m[2][0]*m[2][0]); + + m[0][0] *= fInvLength; + m[1][0] *= fInvLength; + m[2][0] *= fInvLength; + + // compute q1 + float fDot0 = + m[0][0]*m[0][1] + + m[1][0]*m[1][1] + + m[2][0]*m[2][1]; + + m[0][1] -= fDot0*m[0][0]; + m[1][1] -= fDot0*m[1][0]; + m[2][1] -= fDot0*m[2][0]; + + fInvLength = 1.0/sqrt(m[0][1]*m[0][1] + + m[1][1]*m[1][1] + + m[2][1]*m[2][1]); + + m[0][1] *= fInvLength; + m[1][1] *= fInvLength; + m[2][1] *= fInvLength; + + // compute q2 + float fDot1 = + m[0][1]*m[0][2] + + m[1][1]*m[1][2] + + m[2][1]*m[2][2]; + + fDot0 = + m[0][0]*m[0][2] + + m[1][0]*m[1][2] + + m[2][0]*m[2][2]; + + m[0][2] -= fDot0*m[0][0] + fDot1*m[0][1]; + m[1][2] -= fDot0*m[1][0] + fDot1*m[1][1]; + m[2][2] -= fDot0*m[2][0] + fDot1*m[2][1]; + + fInvLength = 1.0/sqrt(m[0][2]*m[0][2] + + m[1][2]*m[1][2] + + m[2][2]*m[2][2]); + + m[0][2] *= fInvLength; + m[1][2] *= fInvLength; + m[2][2] *= fInvLength; +} +//----------------------------------------------------------------------- +void Matrix3::QDUDecomposition (Matrix3& kQ, + Vector3& kD, Vector3& kU) const +{ + // Factor M = QR = QDU where Q is orthogonal, D is diagonal, + // and U is upper triangular with ones on its diagonal. Algorithm uses + // Gram-Schmidt orthogonalization (the QR algorithm). + // + // If M = [ m0 | m1 | m2 ] and Q = [ q0 | q1 | q2 ], then + // + // q0 = m0/|m0| + // q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0| + // q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1| + // + // where |V| indicates length of vector V and A*B indicates dot + // product of vectors A and B. The matrix R has entries + // + // r00 = q0*m0 r01 = q0*m1 r02 = q0*m2 + // r10 = 0 r11 = q1*m1 r12 = q1*m2 + // r20 = 0 r21 = 0 r22 = q2*m2 + // + // so D = diag(r00,r11,r22) and U has entries u01 = r01/r00, + // u02 = r02/r00, and u12 = r12/r11. + + // Q = rotation + // D = scaling + // U = shear + + // D stores the three diagonal entries r00, r11, r22 + // U stores the entries U[0] = u01, U[1] = u02, U[2] = u12 + + // build orthogonal matrix Q + float fInvLength = 1.0/sqrt(m[0][0]*m[0][0] + + m[1][0]*m[1][0] + + m[2][0]*m[2][0]); + kQ[0][0] = m[0][0]*fInvLength; + kQ[1][0] = m[1][0]*fInvLength; + kQ[2][0] = m[2][0]*fInvLength; + + float fDot = kQ[0][0]*m[0][1] + kQ[1][0]*m[1][1] + + kQ[2][0]*m[2][1]; + kQ[0][1] = m[0][1]-fDot*kQ[0][0]; + kQ[1][1] = m[1][1]-fDot*kQ[1][0]; + kQ[2][1] = m[2][1]-fDot*kQ[2][0]; + fInvLength = 1.0/sqrt(kQ[0][1]*kQ[0][1] + kQ[1][1]*kQ[1][1] + + kQ[2][1]*kQ[2][1]); + kQ[0][1] *= fInvLength; + kQ[1][1] *= fInvLength; + kQ[2][1] *= fInvLength; + + fDot = kQ[0][0]*m[0][2] + kQ[1][0]*m[1][2] + + kQ[2][0]*m[2][2]; + kQ[0][2] = m[0][2]-fDot*kQ[0][0]; + kQ[1][2] = m[1][2]-fDot*kQ[1][0]; + kQ[2][2] = m[2][2]-fDot*kQ[2][0]; + fDot = kQ[0][1]*m[0][2] + kQ[1][1]*m[1][2] + + kQ[2][1]*m[2][2]; + kQ[0][2] -= fDot*kQ[0][1]; + kQ[1][2] -= fDot*kQ[1][1]; + kQ[2][2] -= fDot*kQ[2][1]; + fInvLength = 1.0/sqrt(kQ[0][2]*kQ[0][2] + kQ[1][2]*kQ[1][2] + + kQ[2][2]*kQ[2][2]); + kQ[0][2] *= fInvLength; + kQ[1][2] *= fInvLength; + kQ[2][2] *= fInvLength; + + // guarantee that orthogonal matrix has determinant 1 (no reflections) + float fDet = kQ[0][0]*kQ[1][1]*kQ[2][2] + kQ[0][1]*kQ[1][2]*kQ[2][0] + + kQ[0][2]*kQ[1][0]*kQ[2][1] - kQ[0][2]*kQ[1][1]*kQ[2][0] - + kQ[0][1]*kQ[1][0]*kQ[2][2] - kQ[0][0]*kQ[1][2]*kQ[2][1]; + + if ( fDet < 0.0 ) + { + for (int iRow = 0; iRow < 3; iRow++) + for (int iCol = 0; iCol < 3; iCol++) + kQ[iRow][iCol] = -kQ[iRow][iCol]; + } + + // build "right" matrix R + Matrix3 kR; + kR[0][0] = kQ[0][0]*m[0][0] + kQ[1][0]*m[1][0] + + kQ[2][0]*m[2][0]; + kR[0][1] = kQ[0][0]*m[0][1] + kQ[1][0]*m[1][1] + + kQ[2][0]*m[2][1]; + kR[1][1] = kQ[0][1]*m[0][1] + kQ[1][1]*m[1][1] + + kQ[2][1]*m[2][1]; + kR[0][2] = kQ[0][0]*m[0][2] + kQ[1][0]*m[1][2] + + kQ[2][0]*m[2][2]; + kR[1][2] = kQ[0][1]*m[0][2] + kQ[1][1]*m[1][2] + + kQ[2][1]*m[2][2]; + kR[2][2] = kQ[0][2]*m[0][2] + kQ[1][2]*m[1][2] + + kQ[2][2]*m[2][2]; + + // the scaling component + kD[0] = kR[0][0]; + kD[1] = kR[1][1]; + kD[2] = kR[2][2]; + + // the shear component + float fInvD0 = 1.0/kD[0]; + kU[0] = kR[0][1]*fInvD0; + kU[1] = kR[0][2]*fInvD0; + kU[2] = kR[1][2]/kD[1]; +} +//----------------------------------------------------------------------- +float Matrix3::MaxCubicRoot (float afCoeff[3]) +{ + // Spectral norm is for A^T*A, so characteristic polynomial + // P(x) = c[0]+c[1]*x+c[2]*x^2+x^3 has three positive float roots. + // This yields the assertions c[0] < 0 and c[2]*c[2] >= 3*c[1]. + + // quick out for uniform scale (triple root) + const float fOneThird = 1.0/3.0; + const float fEpsilon = 1e-06; + float fDiscr = afCoeff[2]*afCoeff[2] - 3.0*afCoeff[1]; + if ( fDiscr <= fEpsilon ) + return -fOneThird*afCoeff[2]; + + // Compute an upper bound on roots of P(x). This assumes that A^T*A + // has been scaled by its largest entry. + float fX = 1.0; + float fPoly = afCoeff[0]+fX*(afCoeff[1]+fX*(afCoeff[2]+fX)); + if ( fPoly < 0.0 ) + { + // uses a matrix norm to find an upper bound on maximum root + fX = fabs(afCoeff[0]); + float fTmp = 1.0+fabs(afCoeff[1]); + if ( fTmp > fX ) + fX = fTmp; + fTmp = 1.0+fabs(afCoeff[2]); + if ( fTmp > fX ) + fX = fTmp; + } + + // Newton's method to find root + float fTwoC2 = 2.0*afCoeff[2]; + for (int i = 0; i < 16; i++) + { + fPoly = afCoeff[0]+fX*(afCoeff[1]+fX*(afCoeff[2]+fX)); + if ( fabs(fPoly) <= fEpsilon ) + return fX; + + float fDeriv = afCoeff[1]+fX*(fTwoC2+3.0*fX); + fX -= fPoly/fDeriv; + } + + return fX; +} +//----------------------------------------------------------------------- +float Matrix3::SpectralNorm () const +{ + Matrix3 kP; + int iRow, iCol; + float fPmax = 0.0; + for (iRow = 0; iRow < 3; iRow++) + { + for (iCol = 0; iCol < 3; iCol++) + { + kP[iRow][iCol] = 0.0; + for (int iMid = 0; iMid < 3; iMid++) + { + kP[iRow][iCol] += + m[iMid][iRow]*m[iMid][iCol]; + } + if ( kP[iRow][iCol] > fPmax ) + fPmax = kP[iRow][iCol]; + } + } + + float fInvPmax = 1.0/fPmax; + for (iRow = 0; iRow < 3; iRow++) + { + for (iCol = 0; iCol < 3; iCol++) + kP[iRow][iCol] *= fInvPmax; + } + + float afCoeff[3]; + afCoeff[0] = -(kP[0][0]*(kP[1][1]*kP[2][2]-kP[1][2]*kP[2][1]) + + kP[0][1]*(kP[2][0]*kP[1][2]-kP[1][0]*kP[2][2]) + + kP[0][2]*(kP[1][0]*kP[2][1]-kP[2][0]*kP[1][1])); + afCoeff[1] = kP[0][0]*kP[1][1]-kP[0][1]*kP[1][0] + + kP[0][0]*kP[2][2]-kP[0][2]*kP[2][0] + + kP[1][1]*kP[2][2]-kP[1][2]*kP[2][1]; + afCoeff[2] = -(kP[0][0]+kP[1][1]+kP[2][2]); + + float fRoot = MaxCubicRoot(afCoeff); + float fNorm = sqrt(fPmax*fRoot); + return fNorm; +} +//----------------------------------------------------------------------- +void Matrix3::ToAxisAngle (Vector3& rkAxis, float& rfRadians) const +{ + // Let (x,y,z) be the unit-length axis and let A be an angle of rotation. + // The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 where + // I is the identity and + // + // +- -+ + // P = | 0 -z +y | + // | +z 0 -x | + // | -y +x 0 | + // +- -+ + // + // If A > 0, R represents a counterclockwise rotation about the axis in + // the sense of looking from the tip of the axis vector towards the + // origin. Some algebra will show that + // + // cos(A) = (trace(R)-1)/2 and R - R^t = 2*sin(A)*P + // + // In the event that A = pi, R-R^t = 0 which prevents us from extracting + // the axis through P. Instead note that R = I+2*P^2 when A = pi, so + // P^2 = (R-I)/2. The diagonal entries of P^2 are x^2-1, y^2-1, and + // z^2-1. We can solve these for axis (x,y,z). Because the angle is pi, + // it does not matter which sign you choose on the square roots. + + float fTrace = m[0][0] + m[1][1] + m[2][2]; + float fCos = 0.5*(fTrace-1.0); + rfRadians = acos(fCos); // in [0,PI] + + if ( rfRadians > 0.0 ) + { + if ( rfRadians < M_PI ) + { + rkAxis.x = m[2][1]-m[1][2]; + rkAxis.y = m[0][2]-m[2][0]; + rkAxis.z = m[1][0]-m[0][1]; + rkAxis.normalise(); + } + else + { + // angle is PI + float fHalfInverse; + if ( m[0][0] >= m[1][1] ) + { + // r00 >= r11 + if ( m[0][0] >= m[2][2] ) + { + // r00 is maximum diagonal term + rkAxis.x = 0.5*sqrt(m[0][0] - + m[1][1] - m[2][2] + 1.0); + fHalfInverse = 0.5/rkAxis.x; + rkAxis.y = fHalfInverse*m[0][1]; + rkAxis.z = fHalfInverse*m[0][2]; + } + else + { + // r22 is maximum diagonal term + rkAxis.z = 0.5*sqrt(m[2][2] - + m[0][0] - m[1][1] + 1.0); + fHalfInverse = 0.5/rkAxis.z; + rkAxis.x = fHalfInverse*m[0][2]; + rkAxis.y = fHalfInverse*m[1][2]; + } + } + else + { + // r11 > r00 + if ( m[1][1] >= m[2][2] ) + { + // r11 is maximum diagonal term + rkAxis.y = 0.5*sqrt(m[1][1] - + m[0][0] - m[2][2] + 1.0); + fHalfInverse = 0.5/rkAxis.y; + rkAxis.x = fHalfInverse*m[0][1]; + rkAxis.z = fHalfInverse*m[1][2]; + } + else + { + // r22 is maximum diagonal term + rkAxis.z = 0.5*sqrt(m[2][2] - + m[0][0] - m[1][1] + 1.0); + fHalfInverse = 0.5/rkAxis.z; + rkAxis.x = fHalfInverse*m[0][2]; + rkAxis.y = fHalfInverse*m[1][2]; + } + } + } + } + else + { + // The angle is 0 and the matrix is the identity. Any axis will + // work, so just use the x-axis. + rkAxis.x = 1.0; + rkAxis.y = 0.0; + rkAxis.z = 0.0; + } +} +//----------------------------------------------------------------------- +void Matrix3::FromAxisAngle (const Vector3& rkAxis, float fRadians) +{ + float fCos = cos(fRadians); + float fSin = sin(fRadians); + float fOneMinusCos = 1.0-fCos; + float fX2 = rkAxis.x*rkAxis.x; + float fY2 = rkAxis.y*rkAxis.y; + float fZ2 = rkAxis.z*rkAxis.z; + float fXYM = rkAxis.x*rkAxis.y*fOneMinusCos; + float fXZM = rkAxis.x*rkAxis.z*fOneMinusCos; + float fYZM = rkAxis.y*rkAxis.z*fOneMinusCos; + float fXSin = rkAxis.x*fSin; + float fYSin = rkAxis.y*fSin; + float fZSin = rkAxis.z*fSin; + + m[0][0] = fX2*fOneMinusCos+fCos; + m[0][1] = fXYM-fZSin; + m[0][2] = fXZM+fYSin; + m[1][0] = fXYM+fZSin; + m[1][1] = fY2*fOneMinusCos+fCos; + m[1][2] = fYZM-fXSin; + m[2][0] = fXZM-fYSin; + m[2][1] = fYZM+fXSin; + m[2][2] = fZ2*fOneMinusCos+fCos; +} +//----------------------------------------------------------------------- +bool Matrix3::ToEulerAnglesXYZ (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const +{ + // rot = cy*cz -cy*sz sy + // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx + // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy + + rfPAngle = sin(m[0][2]); + if ( rfPAngle < (M_PI * 0.5) ) + { + if ( rfPAngle > -(M_PI * 0.5) ) + { + rfYAngle = atan2(-m[1][2],m[2][2]); + rfRAngle = atan2(-m[0][1],m[0][0]); + return true; + } + else + { + // WARNING. Not a unique solution. + float fRmY = atan2(m[1][0],m[1][1]); + rfRAngle = 0.0; // any angle works + rfYAngle = rfRAngle - fRmY; + return false; + } + } + else + { + // WARNING. Not a unique solution. + float fRpY = atan2(m[1][0],m[1][1]); + rfRAngle = 0.0; // any angle works + rfYAngle = fRpY - rfRAngle; + return false; + } +} +//----------------------------------------------------------------------- +bool Matrix3::ToEulerAnglesXZY (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const +{ + // rot = cy*cz -sz cz*sy + // sx*sy+cx*cy*sz cx*cz -cy*sx+cx*sy*sz + // -cx*sy+cy*sx*sz cz*sx cx*cy+sx*sy*sz + + rfPAngle = asin(-m[0][1]); + if ( rfPAngle < (M_PI*0.5) ) + { + if ( rfPAngle > -(M_PI*0.5) ) + { + rfYAngle = atan2(m[2][1],m[1][1]); + rfRAngle = atan2(m[0][2],m[0][0]); + return true; + } + else + { + // WARNING. Not a unique solution. + float fRmY = atan2(-m[2][0],m[2][2]); + rfRAngle = 0.0; // any angle works + rfYAngle = rfRAngle - fRmY; + return false; + } + } + else + { + // WARNING. Not a unique solution. + float fRpY = atan2(-m[2][0],m[2][2]); + rfRAngle = 0.0; // any angle works + rfYAngle = fRpY - rfRAngle; + return false; + } +} +//----------------------------------------------------------------------- +bool Matrix3::ToEulerAnglesYXZ (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const +{ + // rot = cy*cz+sx*sy*sz cz*sx*sy-cy*sz cx*sy + // cx*sz cx*cz -sx + // -cz*sy+cy*sx*sz cy*cz*sx+sy*sz cx*cy + + rfPAngle = asin(-m[1][2]); + if ( rfPAngle < (M_PI*0.5) ) + { + if ( rfPAngle > -(M_PI*0.5) ) + { + rfYAngle = atan2(m[0][2],m[2][2]); + rfRAngle = atan2(m[1][0],m[1][1]); + return true; + } + else + { + // WARNING. Not a unique solution. + float fRmY = atan2(-m[0][1],m[0][0]); + rfRAngle = 0.0; // any angle works + rfYAngle = rfRAngle - fRmY; + return false; + } + } + else + { + // WARNING. Not a unique solution. + float fRpY = atan2(-m[0][1],m[0][0]); + rfRAngle = 0.0; // any angle works + rfYAngle = fRpY - rfRAngle; + return false; + } +} +//----------------------------------------------------------------------- +bool Matrix3::ToEulerAnglesYZX (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const +{ + // rot = cy*cz sx*sy-cx*cy*sz cx*sy+cy*sx*sz + // sz cx*cz -cz*sx + // -cz*sy cy*sx+cx*sy*sz cx*cy-sx*sy*sz + + rfPAngle = asin(m[1][0]); + if ( rfPAngle < (M_PI*0.5) ) + { + if ( rfPAngle > -(M_PI*0.5) ) + { + rfYAngle = atan2(-m[2][0],m[0][0]); + rfRAngle = atan2(-m[1][2],m[1][1]); + return true; + } + else + { + // WARNING. Not a unique solution. + float fRmY = atan2(m[2][1],m[2][2]); + rfRAngle = 0.0; // any angle works + rfYAngle = rfRAngle - fRmY; + return false; + } + } + else + { + // WARNING. Not a unique solution. + float fRpY = atan2(m[2][1],m[2][2]); + rfRAngle = 0.0; // any angle works + rfYAngle = fRpY - rfRAngle; + return false; + } +} +//----------------------------------------------------------------------- +bool Matrix3::ToEulerAnglesZXY (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const +{ + // rot = cy*cz-sx*sy*sz -cx*sz cz*sy+cy*sx*sz + // cz*sx*sy+cy*sz cx*cz -cy*cz*sx+sy*sz + // -cx*sy sx cx*cy + + rfPAngle = asin(m[2][1]); + if ( rfPAngle < (M_PI*0.5) ) + { + if ( rfPAngle > -(M_PI*0.5) ) + { + rfYAngle = atan2(-m[0][1],m[1][1]); + rfRAngle = atan2(-m[2][0],m[2][2]); + return true; + } + else + { + // WARNING. Not a unique solution. + float fRmY = atan2(m[0][2],m[0][0]); + rfRAngle = 0.0; // any angle works + rfYAngle = rfRAngle - fRmY; + return false; + } + } + else + { + // WARNING. Not a unique solution. + float fRpY = atan2(m[0][2],m[0][0]); + rfRAngle = 0.0; // any angle works + rfYAngle = fRpY - rfRAngle; + return false; + } +} +//----------------------------------------------------------------------- +bool Matrix3::ToEulerAnglesZYX (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const +{ + // rot = cy*cz cz*sx*sy-cx*sz cx*cz*sy+sx*sz + // cy*sz cx*cz+sx*sy*sz -cz*sx+cx*sy*sz + // -sy cy*sx cx*cy + + rfPAngle = asin(-m[2][0]); + if ( rfPAngle < (M_PI*0.5) ) + { + if ( rfPAngle > -(M_PI*0.5) ) + { + rfYAngle = atan2(m[1][0],m[0][0]); + rfRAngle = atan2(m[2][1],m[2][2]); + return true; + } + else + { + // WARNING. Not a unique solution. + float fRmY = atan2(-m[0][1],m[0][2]); + rfRAngle = 0.0; // any angle works + rfYAngle = rfRAngle - fRmY; + return false; + } + } + else + { + // WARNING. Not a unique solution. + float fRpY = atan2(-m[0][1],m[0][2]); + rfRAngle = 0.0; // any angle works + rfYAngle = fRpY - rfRAngle; + return false; + } +} +//----------------------------------------------------------------------- +void Matrix3::FromEulerAnglesXYZ (float fYAngle, float fPAngle, + float fRAngle) +{ + float fCos, fSin; + + fCos = cos(fYAngle); + fSin = sin(fYAngle); + Matrix3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos); + + fCos = cos(fPAngle); + fSin = sin(fPAngle); + Matrix3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos); + + fCos = cos(fRAngle); + fSin = sin(fRAngle); + Matrix3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0); + + *this = kXMat*(kYMat*kZMat); +} +//----------------------------------------------------------------------- +void Matrix3::FromEulerAnglesXZY (float fYAngle, float fPAngle, + float fRAngle) +{ + float fCos, fSin; + + fCos = cos(fYAngle); + fSin = sin(fYAngle); + Matrix3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos); + + fCos = cos(fPAngle); + fSin = sin(fPAngle); + Matrix3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0); + + fCos = cos(fRAngle); + fSin = sin(fRAngle); + Matrix3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos); + + *this = kXMat*(kZMat*kYMat); +} +//----------------------------------------------------------------------- +void Matrix3::FromEulerAnglesYXZ (float fYAngle, float fPAngle, + float fRAngle) +{ + float fCos, fSin; + + fCos = cos(fYAngle); + fSin = sin(fYAngle); + Matrix3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos); + + fCos = cos(fPAngle); + fSin = sin(fPAngle); + Matrix3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos); + + fCos = cos(fRAngle); + fSin = sin(fRAngle); + Matrix3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0); + + *this = kYMat*(kXMat*kZMat); +} +//----------------------------------------------------------------------- +void Matrix3::FromEulerAnglesYZX (float fYAngle, float fPAngle, + float fRAngle) +{ + float fCos, fSin; + + fCos = cos(fYAngle); + fSin = sin(fYAngle); + Matrix3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos); + + fCos = cos(fPAngle); + fSin = sin(fPAngle); + Matrix3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0); + + fCos = cos(fRAngle); + fSin = sin(fRAngle); + Matrix3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos); + + *this = kYMat*(kZMat*kXMat); +} +//----------------------------------------------------------------------- +void Matrix3::FromEulerAnglesZXY (float fYAngle, float fPAngle, + float fRAngle) +{ + float fCos, fSin; + + fCos = cos(fYAngle); + fSin = sin(fYAngle); + Matrix3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0); + + fCos = cos(fPAngle); + fSin = sin(fPAngle); + Matrix3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos); + + fCos = cos(fRAngle); + fSin = sin(fRAngle); + Matrix3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos); + + *this = kZMat*(kXMat*kYMat); +} +//----------------------------------------------------------------------- +void Matrix3::FromEulerAnglesZYX (float fYAngle, float fPAngle, + float fRAngle) +{ + float fCos, fSin; + + fCos = cos(fYAngle); + fSin = sin(fYAngle); + Matrix3 kZMat(fCos,-fSin,0.0,fSin,fCos,0.0,0.0,0.0,1.0); + + fCos = cos(fPAngle); + fSin = sin(fPAngle); + Matrix3 kYMat(fCos,0.0,fSin,0.0,1.0,0.0,-fSin,0.0,fCos); + + fCos = cos(fRAngle); + fSin = sin(fRAngle); + Matrix3 kXMat(1.0,0.0,0.0,0.0,fCos,-fSin,0.0,fSin,fCos); + + *this = kZMat*(kYMat*kXMat); +} +//----------------------------------------------------------------------- +void Matrix3::Tridiagonal (float afDiag[3], float afSubDiag[3]) +{ + // Householder reduction T = Q^t M Q + // Input: + // mat, symmetric 3x3 matrix M + // Output: + // mat, orthogonal matrix Q + // diag, diagonal entries of T + // subd, subdiagonal entries of T (T is symmetric) + + float fA = m[0][0]; + float fB = m[0][1]; + float fC = m[0][2]; + float fD = m[1][1]; + float fE = m[1][2]; + float fF = m[2][2]; + + afDiag[0] = fA; + afSubDiag[2] = 0.0; + if ( fabs(fC) >= EPSILON ) + { + float fLength = sqrt(fB*fB+fC*fC); + float fInvLength = 1.0/fLength; + fB *= fInvLength; + fC *= fInvLength; + float fQ = 2.0*fB*fE+fC*(fF-fD); + afDiag[1] = fD+fC*fQ; + afDiag[2] = fF-fC*fQ; + afSubDiag[0] = fLength; + afSubDiag[1] = fE-fB*fQ; + m[0][0] = 1.0; + m[0][1] = 0.0; + m[0][2] = 0.0; + m[1][0] = 0.0; + m[1][1] = fB; + m[1][2] = fC; + m[2][0] = 0.0; + m[2][1] = fC; + m[2][2] = -fB; + } + else + { + afDiag[1] = fD; + afDiag[2] = fF; + afSubDiag[0] = fB; + afSubDiag[1] = fE; + m[0][0] = 1.0; + m[0][1] = 0.0; + m[0][2] = 0.0; + m[1][0] = 0.0; + m[1][1] = 1.0; + m[1][2] = 0.0; + m[2][0] = 0.0; + m[2][1] = 0.0; + m[2][2] = 1.0; + } +} +//----------------------------------------------------------------------- +bool Matrix3::QLAlgorithm (float afDiag[3], float afSubDiag[3]) +{ + // QL iteration with implicit shifting to reduce matrix from tridiagonal + // to diagonal + + for (int i0 = 0; i0 < 3; i0++) + { + const int iMaxIter = 32; + int iIter; + for (iIter = 0; iIter < iMaxIter; iIter++) + { + int i1; + for (i1 = i0; i1 <= 1; i1++) + { + float fSum = fabs(afDiag[i1]) + + fabs(afDiag[i1+1]); + if ( fabs(afSubDiag[i1]) + fSum == fSum ) + break; + } + if ( i1 == i0 ) + break; + + float fTmp0 = (afDiag[i0+1]-afDiag[i0])/(2.0*afSubDiag[i0]); + float fTmp1 = sqrt(fTmp0*fTmp0+1.0); + if ( fTmp0 < 0.0 ) + fTmp0 = afDiag[i1]-afDiag[i0]+afSubDiag[i0]/(fTmp0-fTmp1); + else + fTmp0 = afDiag[i1]-afDiag[i0]+afSubDiag[i0]/(fTmp0+fTmp1); + float fSin = 1.0; + float fCos = 1.0; + float fTmp2 = 0.0; + for (int i2 = i1-1; i2 >= i0; i2--) + { + float fTmp3 = fSin*afSubDiag[i2]; + float fTmp4 = fCos*afSubDiag[i2]; + if ( fabs(fTmp3) >= fabs(fTmp0) ) + { + fCos = fTmp0/fTmp3; + fTmp1 = sqrt(fCos*fCos+1.0); + afSubDiag[i2+1] = fTmp3*fTmp1; + fSin = 1.0/fTmp1; + fCos *= fSin; + } + else + { + fSin = fTmp3/fTmp0; + fTmp1 = sqrt(fSin*fSin+1.0); + afSubDiag[i2+1] = fTmp0*fTmp1; + fCos = 1.0/fTmp1; + fSin *= fCos; + } + fTmp0 = afDiag[i2+1]-fTmp2; + fTmp1 = (afDiag[i2]-fTmp0)*fSin+2.0*fTmp4*fCos; + fTmp2 = fSin*fTmp1; + afDiag[i2+1] = fTmp0+fTmp2; + fTmp0 = fCos*fTmp1-fTmp4; + + for (int iRow = 0; iRow < 3; iRow++) + { + fTmp3 = m[iRow][i2+1]; + m[iRow][i2+1] = fSin*m[iRow][i2] + + fCos*fTmp3; + m[iRow][i2] = fCos*m[iRow][i2] - + fSin*fTmp3; + } + } + afDiag[i0] -= fTmp2; + afSubDiag[i0] = fTmp0; + afSubDiag[i1] = 0.0; + } + + if ( iIter == iMaxIter ) + { + // should not get here under normal circumstances + return false; + } + } + + return true; +} +//----------------------------------------------------------------------- +void Matrix3::EigenSolveSymmetric (float afEigenvalue[3], + Vector3 akEigenvector[3]) const +{ + Matrix3 kMatrix = *this; + float afSubDiag[3]; + kMatrix.Tridiagonal(afEigenvalue,afSubDiag); + kMatrix.QLAlgorithm(afEigenvalue,afSubDiag); + + for (int i = 0; i < 3; i++) + { + akEigenvector[i][0] = kMatrix[0][i]; + akEigenvector[i][1] = kMatrix[1][i]; + akEigenvector[i][2] = kMatrix[2][i]; + } + + // make eigenvectors form a right--handed system + Vector3 kCross = akEigenvector[1].crossProduct(akEigenvector[2]); + float fDet = akEigenvector[0].dotProduct(kCross); + if ( fDet < 0.0 ) + { + akEigenvector[2][0] = - akEigenvector[2][0]; + akEigenvector[2][1] = - akEigenvector[2][1]; + akEigenvector[2][2] = - akEigenvector[2][2]; + } +} +//----------------------------------------------------------------------- +void Matrix3::TensorProduct (const Vector3& rkU, const Vector3& rkV, + Matrix3& rkProduct) +{ + for (int iRow = 0; iRow < 3; iRow++) + { + for (int iCol = 0; iCol < 3; iCol++) + rkProduct[iRow][iCol] = rkU[iRow]*rkV[iCol]; + } +} + diff --git a/src/Matrix3.h b/src/Matrix3.h new file mode 100644 index 0000000..066992a --- /dev/null +++ b/src/Matrix3.h @@ -0,0 +1,178 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +#ifndef __Matrix3_H__ +#define __Matrix3_H__ + +#include "Vector3.h" + +// NB All code adapted from Wild Magic 0.2 Matrix math (free source code) +// http://www.magic-software.com + +// NOTE. The (x,y,z) coordinate system is assumed to be right-handed. +// Coordinate axis rotation matrices are of the form +// RX = 1 0 0 +// 0 cos(t) -sin(t) +// 0 sin(t) cos(t) +// where t > 0 indicates a counterclockwise rotation in the yz-plane +// RY = cos(t) 0 sin(t) +// 0 1 0 +// -sin(t) 0 cos(t) +// where t > 0 indicates a counterclockwise rotation in the zx-plane +// RZ = cos(t) -sin(t) 0 +// sin(t) cos(t) 0 +// 0 0 1 +// where t > 0 indicates a counterclockwise rotation in the xy-plane. + + +/** A 3x3 matrix which can represent rotations around axes. + @note + All the code is adapted from the Wild Magic 0.2 Matrix + library (http://www.magic-software.com). + @par + The coordinate system is assumed to be right-handed. +*/ +class Matrix3 +{ +public: + // construction + Matrix3 (); + Matrix3 (const float arr[3][3]); + Matrix3 (const Matrix3& rkMatrix); + Matrix3 (float fEntry00, float fEntry01, float fEntry02, + float fEntry10, float fEntry11, float fEntry12, + float fEntry20, float fEntry21, float fEntry22); + + // member access, allows use of construct mat[r][c] + float* operator[] (int iRow) const; + operator float* (); + Vector3 GetColumn (int iCol) const; + void SetColumn(int iCol, const Vector3& vec); + void FromAxes(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis); + + // assignment and comparison + Matrix3& operator= (const Matrix3& rkMatrix); + bool operator== (const Matrix3& rkMatrix) const; + bool operator!= (const Matrix3& rkMatrix) const; + + // arithmetic operations + Matrix3 operator+ (const Matrix3& rkMatrix) const; + Matrix3 operator- (const Matrix3& rkMatrix) const; + Matrix3 operator* (const Matrix3& rkMatrix) const; + Matrix3 operator- () const; + + // matrix * vector [3x3 * 3x1 = 3x1] + Vector3 operator* (const Vector3& rkVector) const; + + // vector * matrix [1x3 * 3x3 = 1x3] + friend Vector3 operator* (const Vector3& rkVector, + const Matrix3& rkMatrix); + + // matrix * scalar + Matrix3 operator* (float fScalar) const; + + // scalar * matrix + friend Matrix3 operator* (float fScalar, const Matrix3& rkMatrix); + + // utilities + Matrix3 Transpose () const; + bool Inverse (Matrix3& rkInverse, float fTolerance = 1e-06) const; + Matrix3 Inverse (float fTolerance = 1e-06) const; + float Determinant () const; + + // singular value decomposition + void SingularValueDecomposition (Matrix3& rkL, Vector3& rkS, + Matrix3& rkR) const; + void SingularValueComposition (const Matrix3& rkL, + const Vector3& rkS, const Matrix3& rkR); + + // Gram-Schmidt orthonormalization (applied to columns of rotation matrix) + void Orthonormalize (); + + // orthogonal Q, diagonal D, upper triangular U stored as (u01,u02,u12) + void QDUDecomposition (Matrix3& rkQ, Vector3& rkD, + Vector3& rkU) const; + + float SpectralNorm () const; + + // matrix must be orthonormal + void ToAxisAngle (Vector3& rkAxis, float& rfRadians) const; + void FromAxisAngle (const Vector3& rkAxis, float fRadians); + + // The matrix must be orthonormal. The decomposition is yaw*pitch*roll + // where yaw is rotation about the Up vector, pitch is rotation about the + // Right axis, and roll is rotation about the Direction axis. + bool ToEulerAnglesXYZ (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const; + bool ToEulerAnglesXZY (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const; + bool ToEulerAnglesYXZ (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const; + bool ToEulerAnglesYZX (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const; + bool ToEulerAnglesZXY (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const; + bool ToEulerAnglesZYX (float& rfYAngle, float& rfPAngle, + float& rfRAngle) const; + void FromEulerAnglesXYZ (float fYAngle, float fPAngle, float fRAngle); + void FromEulerAnglesXZY (float fYAngle, float fPAngle, float fRAngle); + void FromEulerAnglesYXZ (float fYAngle, float fPAngle, float fRAngle); + void FromEulerAnglesYZX (float fYAngle, float fPAngle, float fRAngle); + void FromEulerAnglesZXY (float fYAngle, float fPAngle, float fRAngle); + void FromEulerAnglesZYX (float fYAngle, float fPAngle, float fRAngle); + + // eigensolver, matrix must be symmetric + void EigenSolveSymmetric (float afEigenvalue[3], + Vector3 akEigenvector[3]) const; + + static void TensorProduct (const Vector3& rkU, const Vector3& rkV, + Matrix3& rkProduct); + + static const float EPSILON; + static const Matrix3 ZERO; + static const Matrix3 IDENTITY; + +protected: + // support for eigensolver + void Tridiagonal (float afDiag[3], float afSubDiag[3]); + bool QLAlgorithm (float afDiag[3], float afSubDiag[3]); + + // support for singular value decomposition + static const float ms_fSvdEpsilon; + static const int ms_iSvdMaxIterations; + static void Bidiagonalize (Matrix3& kA, Matrix3& kL, + Matrix3& kR); + static void GolubKahanStep (Matrix3& kA, Matrix3& kL, + Matrix3& kR); + + // support for spectral norm + static float MaxCubicRoot (float afCoeff[3]); + + float m[3][3]; + + // for faster access + friend class Matrix4; +}; + +#endif diff --git a/src/Matrix4.cpp b/src/Matrix4.cpp new file mode 100644 index 0000000..e3aa8d7 --- /dev/null +++ b/src/Matrix4.cpp @@ -0,0 +1,90 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +#include "Matrix4.h" + +#include "Vector3.h" +#include "Matrix3.h" + + +const Matrix4 Matrix4::ZERO( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 ); + +const Matrix4 Matrix4::IDENTITY( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 ); + + +inline float + MINOR(const Matrix4& m, const int r0, const int r1, const int r2, const int c0, const int c1, const int c2) +{ + return m[r0][c0] * (m[r1][c1] * m[r2][c2] - m[r2][c1] * m[r1][c2]) - + m[r0][c1] * (m[r1][c0] * m[r2][c2] - m[r2][c0] * m[r1][c2]) + + m[r0][c2] * (m[r1][c0] * m[r2][c1] - m[r2][c0] * m[r1][c1]); +} + + +Matrix4 Matrix4::adjoint() const +{ + return Matrix4( MINOR(*this, 1, 2, 3, 1, 2, 3), + -MINOR(*this, 0, 2, 3, 1, 2, 3), + MINOR(*this, 0, 1, 3, 1, 2, 3), + -MINOR(*this, 0, 1, 2, 1, 2, 3), + + -MINOR(*this, 1, 2, 3, 0, 2, 3), + MINOR(*this, 0, 2, 3, 0, 2, 3), + -MINOR(*this, 0, 1, 3, 0, 2, 3), + MINOR(*this, 0, 1, 2, 0, 2, 3), + + MINOR(*this, 1, 2, 3, 0, 1, 3), + -MINOR(*this, 0, 2, 3, 0, 1, 3), + MINOR(*this, 0, 1, 3, 0, 1, 3), + -MINOR(*this, 0, 1, 2, 0, 1, 3), + + -MINOR(*this, 1, 2, 3, 0, 1, 2), + MINOR(*this, 0, 2, 3, 0, 1, 2), + -MINOR(*this, 0, 1, 3, 0, 1, 2), + MINOR(*this, 0, 1, 2, 0, 1, 2)); +} + + +float Matrix4::determinant() const +{ + return m[0][0] * MINOR(*this, 1, 2, 3, 1, 2, 3) - + m[0][1] * MINOR(*this, 1, 2, 3, 0, 2, 3) + + m[0][2] * MINOR(*this, 1, 2, 3, 0, 1, 3) - + m[0][3] * MINOR(*this, 1, 2, 3, 0, 1, 2); +} + +Matrix4 Matrix4::inverse() const +{ + return adjoint() * (1.0f / determinant()); +} + + diff --git a/src/Matrix4.h b/src/Matrix4.h new file mode 100644 index 0000000..bc8020b --- /dev/null +++ b/src/Matrix4.h @@ -0,0 +1,437 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +#ifndef __Matrix4__ +#define __Matrix4__ + +#include "Vector3.h" +#include "Matrix3.h" + +/** Class encapsulating a standard 4x4 homogenous matrix. + @remarks + OGRE uses column vectors when applying matrix multiplications, + This means a vector is represented as a single column, 4-row + matrix. This has the effect that the tranformations implemented + by the matrices happens right-to-left e.g. if vector V is to be + transformed by M1 then M2 then M3, the calculation would be + M3 * M2 * M1 * V. The order that matrices are concatenated is + vital since matrix multiplication is not cummatative, i.e. you + can get a different result if you concatenate in the wrong order. + @par + The use of column vectors and right-to-left ordering is the + standard in most mathematical texts, and id the same as used in + OpenGL. It is, however, the opposite of Direct3D, which has + inexplicably chosen to differ from the accepted standard and uses + row vectors and left-to-right matrix multiplication. + @par + OGRE deals with the differences between D3D and OpenGL etc. + internally when operating through different render systems. OGRE + users only need to conform to standard maths conventions, i.e. + right-to-left matrix multiplication, (OGRE transposes matrices it + passes to D3D to compensate). + @par + The generic form M * V which shows the layout of the matrix + entries is shown below: +
+            [ m[0][0]  m[0][1]  m[0][2]  m[0][3] ]   {x}
+            | m[1][0]  m[1][1]  m[1][2]  m[1][3] | * {y}
+            | m[2][0]  m[2][1]  m[2][2]  m[2][3] |   {z}
+            [ m[3][0]  m[3][1]  m[3][2]  m[3][3] ]   {1}
+        
+*/ +class Matrix4 +{ +protected: + /// The matrix entries, indexed by [row][col]. + union { + float m[4][4]; + float _m[16]; + }; +public: + /** Default constructor. + @note + It does NOT initialize the matrix for efficiency. + */ + inline Matrix4() + { + } + + inline Matrix4( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33 ) + { + m[0][0] = m00; + m[0][1] = m01; + m[0][2] = m02; + m[0][3] = m03; + m[1][0] = m10; + m[1][1] = m11; + m[1][2] = m12; + m[1][3] = m13; + m[2][0] = m20; + m[2][1] = m21; + m[2][2] = m22; + m[2][3] = m23; + m[3][0] = m30; + m[3][1] = m31; + m[3][2] = m32; + m[3][3] = m33; + } + + /* + inline operator float* (void) + { + return _m; + } + + inline operator const float* (void) + { + return _m; + } + */ + + inline float* operator [] ( unsigned iRow ) + { + assert( iRow < 4 ); + return m[iRow]; + } + + inline const float *const operator [] ( unsigned iRow ) const + { + assert( iRow < 4 ); + return m[iRow]; + } + + inline Matrix4 concatenate(const Matrix4 &m2) const + { + Matrix4 r; + r.m[0][0] = m[0][0] * m2.m[0][0] + m[0][1] * m2.m[1][0] + m[0][2] * m2.m[2][0] + m[0][3] * m2.m[3][0]; + r.m[0][1] = m[0][0] * m2.m[0][1] + m[0][1] * m2.m[1][1] + m[0][2] * m2.m[2][1] + m[0][3] * m2.m[3][1]; + r.m[0][2] = m[0][0] * m2.m[0][2] + m[0][1] * m2.m[1][2] + m[0][2] * m2.m[2][2] + m[0][3] * m2.m[3][2]; + r.m[0][3] = m[0][0] * m2.m[0][3] + m[0][1] * m2.m[1][3] + m[0][2] * m2.m[2][3] + m[0][3] * m2.m[3][3]; + + r.m[1][0] = m[1][0] * m2.m[0][0] + m[1][1] * m2.m[1][0] + m[1][2] * m2.m[2][0] + m[1][3] * m2.m[3][0]; + r.m[1][1] = m[1][0] * m2.m[0][1] + m[1][1] * m2.m[1][1] + m[1][2] * m2.m[2][1] + m[1][3] * m2.m[3][1]; + r.m[1][2] = m[1][0] * m2.m[0][2] + m[1][1] * m2.m[1][2] + m[1][2] * m2.m[2][2] + m[1][3] * m2.m[3][2]; + r.m[1][3] = m[1][0] * m2.m[0][3] + m[1][1] * m2.m[1][3] + m[1][2] * m2.m[2][3] + m[1][3] * m2.m[3][3]; + + r.m[2][0] = m[2][0] * m2.m[0][0] + m[2][1] * m2.m[1][0] + m[2][2] * m2.m[2][0] + m[2][3] * m2.m[3][0]; + r.m[2][1] = m[2][0] * m2.m[0][1] + m[2][1] * m2.m[1][1] + m[2][2] * m2.m[2][1] + m[2][3] * m2.m[3][1]; + r.m[2][2] = m[2][0] * m2.m[0][2] + m[2][1] * m2.m[1][2] + m[2][2] * m2.m[2][2] + m[2][3] * m2.m[3][2]; + r.m[2][3] = m[2][0] * m2.m[0][3] + m[2][1] * m2.m[1][3] + m[2][2] * m2.m[2][3] + m[2][3] * m2.m[3][3]; + + r.m[3][0] = m[3][0] * m2.m[0][0] + m[3][1] * m2.m[1][0] + m[3][2] * m2.m[2][0] + m[3][3] * m2.m[3][0]; + r.m[3][1] = m[3][0] * m2.m[0][1] + m[3][1] * m2.m[1][1] + m[3][2] * m2.m[2][1] + m[3][3] * m2.m[3][1]; + r.m[3][2] = m[3][0] * m2.m[0][2] + m[3][1] * m2.m[1][2] + m[3][2] * m2.m[2][2] + m[3][3] * m2.m[3][2]; + r.m[3][3] = m[3][0] * m2.m[0][3] + m[3][1] * m2.m[1][3] + m[3][2] * m2.m[2][3] + m[3][3] * m2.m[3][3]; + + return r; + } + + /** Matrix concatenation using '*'. + */ + inline Matrix4 operator * ( const Matrix4 &m2 ) const + { + return concatenate( m2 ); + } + + /** Vector transformation using '*'. + @remarks + Transforms the given 3-D vector by the matrix, projecting the + result back into w = 1. + @note + This means that the initial w is considered to be 1.0, + and then all the tree elements of the resulting 3-D vector are + divided by the resulting w. + */ + inline Vector3 operator * ( const Vector3 &v ) const + { + Vector3 r; + + float fInvW = 1.0 / ( m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] ); + + r.x = ( m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] ) * fInvW; + r.y = ( m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] ) * fInvW; + r.z = ( m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] ) * fInvW; + + return r; + } + + /** Matrix addition. + */ + inline Matrix4 operator + ( const Matrix4 &m2 ) const + { + Matrix4 r; + + r.m[0][0] = m[0][0] + m2.m[0][0]; + r.m[0][1] = m[0][1] + m2.m[0][1]; + r.m[0][2] = m[0][2] + m2.m[0][2]; + r.m[0][3] = m[0][3] + m2.m[0][3]; + + r.m[1][0] = m[1][0] + m2.m[1][0]; + r.m[1][1] = m[1][1] + m2.m[1][1]; + r.m[1][2] = m[1][2] + m2.m[1][2]; + r.m[1][3] = m[1][3] + m2.m[1][3]; + + r.m[2][0] = m[2][0] + m2.m[2][0]; + r.m[2][1] = m[2][1] + m2.m[2][1]; + r.m[2][2] = m[2][2] + m2.m[2][2]; + r.m[2][3] = m[2][3] + m2.m[2][3]; + + r.m[3][0] = m[3][0] + m2.m[3][0]; + r.m[3][1] = m[3][1] + m2.m[3][1]; + r.m[3][2] = m[3][2] + m2.m[3][2]; + r.m[3][3] = m[3][3] + m2.m[3][3]; + + return r; + } + + /** Matrix subtraction. + */ + inline Matrix4 operator - ( const Matrix4 &m2 ) const + { + Matrix4 r; + r.m[0][0] = m[0][0] - m2.m[0][0]; + r.m[0][1] = m[0][1] - m2.m[0][1]; + r.m[0][2] = m[0][2] - m2.m[0][2]; + r.m[0][3] = m[0][3] - m2.m[0][3]; + + r.m[1][0] = m[1][0] - m2.m[1][0]; + r.m[1][1] = m[1][1] - m2.m[1][1]; + r.m[1][2] = m[1][2] - m2.m[1][2]; + r.m[1][3] = m[1][3] - m2.m[1][3]; + + r.m[2][0] = m[2][0] - m2.m[2][0]; + r.m[2][1] = m[2][1] - m2.m[2][1]; + r.m[2][2] = m[2][2] - m2.m[2][2]; + r.m[2][3] = m[2][3] - m2.m[2][3]; + + r.m[3][0] = m[3][0] - m2.m[3][0]; + r.m[3][1] = m[3][1] - m2.m[3][1]; + r.m[3][2] = m[3][2] - m2.m[3][2]; + r.m[3][3] = m[3][3] - m2.m[3][3]; + + return r; + } + + /** Tests 2 matrices for equality. + */ + inline bool operator == ( const Matrix4& m2 ) const + { + if( + m[0][0] != m2.m[0][0] || m[0][1] != m2.m[0][1] || m[0][2] != m2.m[0][2] || m[0][3] != m2.m[0][3] || + m[1][0] != m2.m[1][0] || m[1][1] != m2.m[1][1] || m[1][2] != m2.m[1][2] || m[1][3] != m2.m[1][3] || + m[2][0] != m2.m[2][0] || m[2][1] != m2.m[2][1] || m[2][2] != m2.m[2][2] || m[2][3] != m2.m[2][3] || + m[3][0] != m2.m[3][0] || m[3][1] != m2.m[3][1] || m[3][2] != m2.m[3][2] || m[3][3] != m2.m[3][3] ) + return false; + return true; + } + + /** Tests 2 matrices for inequality. + */ + inline bool operator != ( Matrix4& m2 ) const + { + if( + m[0][0] != m2.m[0][0] || m[0][1] != m2.m[0][1] || m[0][2] != m2.m[0][2] || m[0][3] != m2.m[0][3] || + m[1][0] != m2.m[1][0] || m[1][1] != m2.m[1][1] || m[1][2] != m2.m[1][2] || m[1][3] != m2.m[1][3] || + m[2][0] != m2.m[2][0] || m[2][1] != m2.m[2][1] || m[2][2] != m2.m[2][2] || m[2][3] != m2.m[2][3] || + m[3][0] != m2.m[3][0] || m[3][1] != m2.m[3][1] || m[3][2] != m2.m[3][2] || m[3][3] != m2.m[3][3] ) + return true; + return false; + } + + /** Assignment from 3x3 matrix. + */ + inline void operator = ( const Matrix3& mat3 ) + { + m[0][0] = mat3.m[0][0]; m[0][1] = mat3.m[0][1]; m[0][2] = mat3.m[0][2]; + m[1][0] = mat3.m[1][0]; m[1][1] = mat3.m[1][1]; m[1][2] = mat3.m[1][2]; + m[2][0] = mat3.m[2][0]; m[2][1] = mat3.m[2][1]; m[2][2] = mat3.m[2][2]; + } + + inline Matrix4 transpose(void) const + { + return Matrix4(m[0][0], m[1][0], m[2][0], m[3][0], + m[0][1], m[1][1], m[2][1], m[3][1], + m[0][2], m[1][2], m[2][2], m[3][2], + m[0][3], m[1][3], m[2][3], m[3][3]); + } + + /* + ----------------------------------------------------------------------- + Translation Transformation + ----------------------------------------------------------------------- + */ + /** Sets the translation transformation part of the matrix. + */ + inline void setTrans( const Vector3& v ) + { + m[0][3] = v.x; + m[1][3] = v.y; + m[2][3] = v.z; + } + + /** Builds a translation matrix + */ + inline void makeTrans( const Vector3& v ) + { + m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = v.x; + m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = v.y; + m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = v.z; + m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; + } + + inline void makeTrans( float tx, float ty, float tz ) + { + m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = tx; + m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = ty; + m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = tz; + m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; + } + + /** Gets a translation matrix. + */ + inline static Matrix4 getTrans( const Vector3& v ) + { + Matrix4 r; + + r.m[0][0] = 1.0; r.m[0][1] = 0.0; r.m[0][2] = 0.0; r.m[0][3] = v.x; + r.m[1][0] = 0.0; r.m[1][1] = 1.0; r.m[1][2] = 0.0; r.m[1][3] = v.y; + r.m[2][0] = 0.0; r.m[2][1] = 0.0; r.m[2][2] = 1.0; r.m[2][3] = v.z; + r.m[3][0] = 0.0; r.m[3][1] = 0.0; r.m[3][2] = 0.0; r.m[3][3] = 1.0; + + return r; + } + + /** Gets a translation matrix - variation for not using a vector. + */ + inline static Matrix4 getTrans( float t_x, float t_y, float t_z ) + { + Matrix4 r; + + r.m[0][0] = 1.0; r.m[0][1] = 0.0; r.m[0][2] = 0.0; r.m[0][3] = t_x; + r.m[1][0] = 0.0; r.m[1][1] = 1.0; r.m[1][2] = 0.0; r.m[1][3] = t_y; + r.m[2][0] = 0.0; r.m[2][1] = 0.0; r.m[2][2] = 1.0; r.m[2][3] = t_z; + r.m[3][0] = 0.0; r.m[3][1] = 0.0; r.m[3][2] = 0.0; r.m[3][3] = 1.0; + + return r; + } + + /* + ----------------------------------------------------------------------- + Scale Transformation + ----------------------------------------------------------------------- + */ + /** Sets the scale part of the matrix. + */ + inline void setScale( const Vector3& v ) + { + m[0][0] = v.x; + m[1][1] = v.y; + m[2][2] = v.z; + } + + /** Gets a scale matrix. + */ + inline static Matrix4 getScale( const Vector3& v ) + { + Matrix4 r; + r.m[0][0] = v.x; r.m[0][1] = 0.0; r.m[0][2] = 0.0; r.m[0][3] = 0.0; + r.m[1][0] = 0.0; r.m[1][1] = v.y; r.m[1][2] = 0.0; r.m[1][3] = 0.0; + r.m[2][0] = 0.0; r.m[2][1] = 0.0; r.m[2][2] = v.z; r.m[2][3] = 0.0; + r.m[3][0] = 0.0; r.m[3][1] = 0.0; r.m[3][2] = 0.0; r.m[3][3] = 1.0; + + return r; + } + + /** Gets a scale matrix - variation for not using a vector. + */ + inline static Matrix4 getScale( float s_x, float s_y, float s_z ) + { + Matrix4 r; + r.m[0][0] = s_x; r.m[0][1] = 0.0; r.m[0][2] = 0.0; r.m[0][3] = 0.0; + r.m[1][0] = 0.0; r.m[1][1] = s_y; r.m[1][2] = 0.0; r.m[1][3] = 0.0; + r.m[2][0] = 0.0; r.m[2][1] = 0.0; r.m[2][2] = s_z; r.m[2][3] = 0.0; + r.m[3][0] = 0.0; r.m[3][1] = 0.0; r.m[3][2] = 0.0; r.m[3][3] = 1.0; + + return r; + } + + /** Extracts the rotation / scaling part of the Matrix as a 3x3 matrix. + @param m3x3 Destination Matrix3 + */ + inline void extract3x3Matrix(Matrix3& m3x3) const + { + m3x3.m[0][0] = m[0][0]; + m3x3.m[0][1] = m[0][1]; + m3x3.m[0][2] = m[0][2]; + m3x3.m[1][0] = m[1][0]; + m3x3.m[1][1] = m[1][1]; + m3x3.m[1][2] = m[1][2]; + m3x3.m[2][0] = m[2][0]; + m3x3.m[2][1] = m[2][1]; + m3x3.m[2][2] = m[2][2]; + + } + + static const Matrix4 ZERO; + static const Matrix4 IDENTITY; + + inline Matrix4 operator*(float scalar) + { + return Matrix4( + scalar*m[0][0], scalar*m[0][1], scalar*m[0][2], scalar*m[0][3], + scalar*m[1][0], scalar*m[1][1], scalar*m[1][2], scalar*m[1][3], + scalar*m[2][0], scalar*m[2][1], scalar*m[2][2], scalar*m[2][3], + scalar*m[3][0], scalar*m[3][1], scalar*m[3][2], scalar*m[3][3]); + } + + /** Function for writing to a stream. + */ + inline friend std::ostream& operator << + ( std::ostream& o, const Matrix4& m ) + { + o << "Matrix4("; + for (int i = 0; i < 4; ++i) + { + o << " row" << i << "{"; + for(int j = 0; j < 4; ++j) + { + o << m[i][j] << " "; + } + o << "}"; + } + o << ")"; + return o; + } + + Matrix4 adjoint() const; + float determinant() const; + Matrix4 inverse() const; + +}; + +#endif diff --git a/src/Mesh.cpp b/src/Mesh.cpp new file mode 100644 index 0000000..67a1118 --- /dev/null +++ b/src/Mesh.cpp @@ -0,0 +1,950 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Mesh.h" + +#define SWAP_NORMALS_NO + +Mesh::Mesh(const QString& filename,const QString& name, bool checkVBO, int mode) + : Entity(name), hasNormals(false), hasTextCoord(false), Binfo(true) +{ + ///Initialisation des variables + useVBO=(glewIsSupported("GL_ARB_vertex_buffer_object") & checkVBO); + + fName=filename; + + if (mode==0) + position.x=-1.0; + else if (mode==1) + position.x=-0.51; + else position.x=0.0; + position.y=0.65; + position.z=-1.; + + ///Initialisation du compteur de chargement + double debut, fin = clock(); + debut = clock(); + if(filename.contains("off")) + loadOFF(filename); + else if(filename.contains("gts")) + loadGTS(filename); + else if(filename.contains("obj")) + loadOBJ(filename); + else if(filename.contains("3ds")) + load3DS(filename); + else if(filename.contains("ply")) + loadPLY(filename); + + if (!hasNormals) + computeNormals(); + + normalize(); + + if (useVBO) + createVBO(); + + fin = clock(); + time = (fin - debut) / CLOCKS_PER_SEC; +} + +void Mesh::loadPLY(const QString& filename) +{ + QFile plyFile(filename); + if(!plyFile.open(QIODevice::ReadOnly)) + { + std::cerr << "erreur :Chargement PLY : " << filename.toStdString() << std::endl; + return; + } + + QString mot, header; + QTextStream in(&plyFile); + int nofVertices=0, nofFaces=0; + in >> header; + if(header != "ply") + { + std::cerr << "Wrong header = " << header.toStdString() << std::endl; + return; + } + bool end_header =false; + bool isAscii; + +// Lecture de l'header + while(!end_header) + { + in >> header; + if(header == "format") + { + in >> header; + std::cout<> nofVertices; + } + if(header == "face") + { + in >> nofFaces; + } + if(header == "end_header") + end_header=true; + } + + if (nofVertices ==0 | nofFaces==0) + { + std::cerr << "erreur : l'en-tête du fichier est incorrecte : Sommets : " <> vect.x >> vect.y >> vect.z; + // on place le vecteur v dans mVertices qui contient tout les sommets + mVertices.push_back(vect); + } + + // Pour toutes les faces du fichier + for(int i=0 ; i> nb >> id0 >> id1 >> id2; + // on verrifie que nb = 3 + assert(nb==3); + // on place les sommets dans mFaces qui contient toute les faces + #ifdef SWAP_NORMALS + mFaces.push_back(FaceIndex(id2, id1, id0)); + #else + mFaces.push_back(FaceIndex(id0, id1, id2)); + #endif + } + + //Pour les coordonnées de textures + float u,v; + for(int i=0 ; i>u >> v; + mVertices[i].texcoord[0] = u; + mVertices[i].texcoord[1] = v; + } + plyFile.close(); + } + else + { + std::cout<<"Le format binaire des ply n'est pas pris en compte."< vect_id,vect_norm; + std::vectorvect_coordt; + std::vector vertices_prov; + std::vector normales_prov; + std::vector indiceNorprov; + std::vector coordtex_prov; + std::vector indiceCTprov; + Vector3 indNorprov, indCTprov; + QString m,fc, header; + ////////////////////////////////////////////// + // Les éléments du fichier sont chargé dans la variable 'in' + QTextStream in(&objFile); + + // Boucle de lecture du fichier : tant qu'on a pas atteind la fin ! + while(!in.atEnd()) + { + //Lecture du premier caractère stocké dans la variable 'header' + in >> header; + /* vertex */ + if(header == "v") + { + //lecture des coordonnées du sommet + in >> vertice.x >> vertice.y >> vertice.z; + //On stock les coordonnées dans mVertices => au cas ou l'objet n'a pas de normales pré calculé + mVertices.push_back(vertice); + //On stock les coordonnées dans vertices_prov => au cas ou l'objet a des normales pré calculé + vertices_prov.push_back(vertice); + //On compte le nombre de sommets + v++; + //On passe a la ligne suivante + header = in.readLine(); + } + /* texture coords. */ + else if(header == "vt") + { + in >> vertice.x >> vertice.y >> vertice.z; + // On place les coordonnées de texture(généralement seulement x et y) + coordtex_prov.push_back(vertice); + //On compte le nombre de coordonnées + vt++; + hasTextCoord = true; + } + /* normal vector */ + else if(header == "vn") + { + //idem avec les normales + in >> vertice.x >> vertice.y >> vertice.z; + normales_prov.push_back(vertice); + vn++; + hasNormals = true; + header = in.readLine(); + } + /* face */ + else if(header == "f") + { + header = in.readLine(); + //on initialise i à 1 car on ne sait pas combien il y aura de sommet par face + i =1; + // on 'découpe' chaque portion contenant vertices/coortex/normale + m = header.section (' ',i,i); + // le premier élément du vecteur d'index est à zéro, il contiandra le nombre de sommets sur cette face + vect_id.push_back(0); + // lecture de chaque groupe vertices/coortex/normale de la face + while(!m.isEmpty()) + { + i++; + // On recherche di le groupe contien '//' : vertice et normale,(1,1) étant la deuxieme partie (les normales) + fc = m.section ("//",1,1); + if (!fc.isEmpty()) + { + id_norm = fc.toInt(); + //(0,0) est la premiere partie (les vertices) + fc = m.section ("//",0,0); + id_face = fc.toInt(); + } + else + { + // Sinon on cherche s'il y a au moins un '/' + fc = m.section ("/",1,1); + if (!fc.isEmpty()) + { + // s'il y en a un, la premiere partie (1,1) sera les coordonnées de texture + id_coordt = fc.toInt(); + // la premiere partie (0,0) sera les vertices + fc = m.section ("/",0,0); + id_face = fc.toInt(); + // on cherche s'il y a une troisieme partie (2,2) : les normales + fc = m.section ("/",2,2); + if (!fc.isEmpty()) id_norm = fc.toInt(); + } + else + { + // s'il n'y a pas de '/' c'est qu'il n'y a que les indices des sommets + id_face = m.toInt(); + } + } + // on enleve 1 aux indices pour que ça coincide avec un tableau en C++ + vect_id.push_back(id_face-1); + vect_norm.push_back(id_norm-1); + vect_coordt.push_back(id_coordt-1); + // puis cherche le prochain groupe vertices/coortex/normale de cette face + m = header.section (' ',i,i); + } + i--; + // on stock le nombre de sommet dans cette face + vect_id[0]=i; + //On parcours tout les sommets de la face en partant du 2ème + for (int j=2;jnb_max) + nb_max=i; + //calcul du nombre de facettes + f++; + } + // groups + else if(header == "g") + { + g++; + header = in.readLine(); + } + } + // Si l'objet a ses propres coordonnées de texture + taille=mFaces.size(); + if (hasNormals) + { + // On efface les vertices déjà entré + mVertices.clear(); + for (i=0;i Ça permet de mettre au même niveau les + // vertices avec les normales calculé, et celles avec les normales recopiés du fichier + mVertices.clear(); + taille=mFaces.size(); + //Pour toute les faces + for (i=0;i erreur si non trouve + if(!offFile.open(QIODevice::ReadOnly)) + { + std::cerr << "erreur : load OFF : " << filename.toStdString() << std::endl; + return; + } + //Lecture du fichier dans la variable "in" + QTextStream in(&offFile); + + //Declare une variable de type String : "header" + QString header; + + //met le premier mot de "in" dans "header" + in >> header; + + // le premier mot doit etre "OFF" + if(header != "OFF") + { + std::cerr << "Wrong header = " << header.toStdString() << std::endl; + return; + } + + //Nombre de Vertices, Nombre de Face et null + int nofVertices, nofFaces, inull; + // nombre de sommet par face, sommet1, sommet2 , sommet3 + int nb, id0, id1, id2; + //Vecteur size 3 + Vector3 v; + //Place le nombre de vertices totale et de faces totale contenu dans la deuxieme lignes, le dernier est 0 + in >> nofVertices >> nofFaces >> inull; + + // Pour tous les sommets du fichier + for(int i=0 ; i> v.x >> v.y >> v.z; + // on place le vecteur v dans mVertices qui contient tout les sommets + mVertices.push_back(v); + } + + // Pour toutes les faces du fichier + for(int i=0 ; i> nb >> id0 >> id1 >> id2; + // on verrifie que nb = 3 + assert(nb==3); + // on place les sommets dans mFaces qui contient toute les faces +#ifdef SWAP_NORMALS + mFaces.push_back(FaceIndex(id2, id1, id0)); +#else + mFaces.push_back(FaceIndex(id0, id1, id2)); +#endif + + } + // on ferme le fichier + offFile.close(); +} + +void Mesh::loadGTS(const QString& filename) +{ + QFile gtsFile(filename); + std::vector< std::pair > lEdges; + + if(!gtsFile.open(QIODevice::ReadOnly)) + { + std::cerr << "erreur : load GTS : " << filename.toStdString() << std::endl; + return; + } + + QTextStream in(>sFile); + QString header; + + int nofVertices, nofEdges, nofFaces; + int id0, id1, id2; + Vector3 v; + + in >> nofVertices >> nofEdges >> nofFaces; + + for(int i=0 ; i> v.x >> v.y >> v.z; + mVertices.push_back(v); + } + + for(int i=0 ; i> id0 >> id1; + lEdges.push_back( std::pair(id0-1,id1-1) ); + + } + + for(int i=0 ; i> id0 >> id1 >> id2; +#ifdef SWAP_NORMALS + mFaces.push_back(FaceIndex(lEdges[id2-1].first, lEdges[id1-1].first, lEdges[id0-1].first)); +#else + mFaces.push_back(FaceIndex(lEdges[id0-1].first, lEdges[id1-1].first, lEdges[id2-1].first)); +#endif + } + gtsFile.close(); +} + +void Mesh::computeNormals(void) +{ + // compute normals + Vector3 f_normal; + Vector3 p0, p1, p2,p3; + + for(FaceIndexArray::iterator f_iter = mFaces.begin() ; f_iter!=mFaces.end() ; ++f_iter) + { + p0 = mVertices[f_iter->indexes[2]].position; + p1 = mVertices[f_iter->indexes[1]].position; + p2 = mVertices[f_iter->indexes[0]].position; + f_normal = (p1-p0).crossProduct(p2-p0); + f_normal.normalise(); + mVertices[f_iter->indexes[2]].normal += f_normal; + mVertices[f_iter->indexes[1]].normal += f_normal; + mVertices[f_iter->indexes[0]].normal += f_normal; + } + + for(VertexArray::iterator v_iter = mVertices.begin() ; v_iter!=mVertices.end() ; ++v_iter) + { + v_iter->normal.normalise(); + } +} + +void Mesh::normalize(void) +{ + Vector3 min(1e99, 1e99, 1e99); + Vector3 max(-1e99, -1e99, -1e99); + + for(VertexArray::iterator v_iter = mVertices.begin() ; v_iter!=mVertices.end() ; ++v_iter) + { + min.makeFloor(v_iter->position); + max.makeCeil(v_iter->position); + } + + Vector3 diff = max - min; + float scale = diff.x > diff.y ? (diff.x > diff.z ? diff.x : diff.y) : (diff.y>diff.z ? diff.y : diff.z); + scale = 1./scale; + for(VertexArray::iterator v_iter = mVertices.begin() ; v_iter!=mVertices.end() ; ++v_iter) + { + v_iter->position -= min; + v_iter->position *= scale; + } +} + +Mesh::~Mesh() +{ + if (useVBO) + deleteVBO(); +} + +void Mesh::deleteVBO(void) +{ + glDeleteBuffers(1, &m_indexBuffer); + glDeleteBuffers(1, &m_vertexBuffer); + glDeleteBuffers(1, &m_normalBuffer); + glDeleteBuffers(1, &m_texCoordBuffer); +} + +void Mesh::createVBO(void) +{ + // Calcul de la taille qu'occupera le tableau d'index + GLsizeiptr IndexSize = mFaces.size() *3 * sizeof(GLuint); + // Calcul de la taille qu'occupera le tableau de sommets (et de normales) + GLsizeiptr PositionSize = mVertices.size() * 3 * sizeof(GLfloat); + // Calcul de la taille qu'occupera le tableau de coordonnées de texture + GLsizeiptr CTSize = mVertices.size() * 2 * sizeof(GLfloat); + // Nombre d'élément dans le tableau de sommets + int taille = mVertices.size(); + // Création et allocation du tableau de sommets qui sera envoyé à la carte graphique + float *PositionData; + PositionData = new float [taille*3]; + // Création et allocation du tableau de normales qui sera envoyé à la carte graphique + float *NormalData; + NormalData = new float [taille*3]; + // Création et allocation du tableau de coordonnées de textures qui sera envoyé à la carte graphique + float *CTData; + CTData = new float [taille*2]; + // Chargement des valeurs dans les tableaux qu'on vien de créer + for (int i=0;i Mesh::getVertexArray(){ + std::vector vect; + int taille= mVertices.size(); + for(int i=0;icosZ2) normalVect=-normalVect; + + + + + float distance = fabsf(normalVect.x*startPosition.x+normalVect.y*startPosition.y+normalVect.z*startPosition.z); + + if(nbPass==1) + { + if(maxdgetRow(); + //coordonnés de notre plan dans la matrice densité + densityCoord.x = (int)floor((ro)*(dim-1)/(3.1416)); + densityCoord.y = (int)floor((phi+3.1416)*(dim-1)/(3.1416*2)); + densityCoord.z = (int)floor((distance)*(dim-1)/(maxd)); + for(int covOfX = -coverage; covOfX <= coverage; covOfX++) + { + for(int covOfY = -coverage; covOfY <= coverage; covOfY++) + { + for(int covOfZ = -coverage; covOfZ <= coverage; covOfZ++) + { + if( densityCoord.x+covOfX=0 && densityCoord.y+covOfY>=0 && densityCoord.z+covOfZ>=0) + { + + int neighbourDist=abs(covOfX); + if(neighbourDistfill( (int) densityCoord.x+covOfX, (int) densityCoord.y+covOfY, + (int) densityCoord.z+covOfZ, area*pow(0.8,neighbourDist)); + } + } + } + } + } + } + } + pDensity->setDistanceMax( maxd); +} + diff --git a/src/Mesh.h b/src/Mesh.h new file mode 100644 index 0000000..e60cb77 --- /dev/null +++ b/src/Mesh.h @@ -0,0 +1,206 @@ +#ifndef _Mesh_h_ +#define _Mesh_h_ + +#include + +#include +#include "OpenGL.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "Color.h" +#include "Entity.h" +#include "Density.h" + + +/** Classe representant un objet sous la forme d'un maillage. + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Mesh : public Entity +{ +public: + +/** @name Mesh + * @brief Constructeur : Charge un objet 3ds,off ou obj a partir du fichier filename + * @param filename nom du fichier a charger + */ + Mesh(const QString& filename, const QString& name = "", bool checkVBO=true, int mode=0); + + virtual ~Mesh(); + +/** @name load3DS + * @brief Charge un objet de type .3ds + * @param filename : chemin d'accès de l'objet +*/ + void load3DS(const QString& filename); + +/** @name loadOFF + * @brief Charge un objet de type .off + * @param filename : chemin d'accès de l'objet +*/ + void loadOFF(const QString& filename); + +/** @name loadGTS + * @brief Charge un objet de type .gts + * @param filename : chemin d'accès de l'objet +*/ + void loadGTS(const QString& filename); + +/** @name loadOBJ + * @brief Charge un objet de type .obj + * @param filename : chemin d'accès de l'objet +*/ + void loadOBJ(const QString& filename); + +/** @name loadPLY + * @brief Charge un objet de type .ply + * @param filename : chemin d'accès de l'objet +*/ + void loadPLY(const QString& filename); + + virtual void deleteVBO(void); + +/** @name afficheInfo + * @brief Active/Désactive l'affichage des informations à l'écran, ou place l'affichage + * @param mode : Selection + * @p 1 : place l'information en x=-0.51 + * @p 2 : place l'information en x=-1.05 + * @p 3 : place l'information en x=0.0 + * @p 4 : Désactive l'affichage + * @p autre : Active/Désactive l'affichage + */ + virtual void afficheInfoM(int mode); + +/** @name fillDensity + * @brief Permet de remplir la Densité en fonction des normales de l'objet. + * @param coverage : indice de couverture + * @param pDensity : matrice de densité + */ + virtual void fillDensity(int coverage, Density *pDensity); +protected: + + /** Methode chargee du trace de la geometrie de l'objet. + Le trace doit utiliser les vertex array + */ + virtual void drawGeometry(void); + virtual std::vector getVertexArray(); + +/** @name getCenterM + * @brief retourne dans un vector, le centre de gravité de l'objet + * @return un Vector3 contenant la position X,Y,Z du centre de gravité + */ + + virtual Vector3 getCenterM(void); + long filelength(int f); + + +protected: +/** @name: computeNormals + * @brief Calcul les normales + * @param filename: chemin d'accès de l'objet +*/ + void computeNormals(void); + void normalize(void); + void prepareForShadowVolume(void); + + /** Represente un sommet du maillage + */ + struct Vertex + { + Vertex(void) : position(Vector3::ZERO), normal(Vector3::ZERO) {}; + Vertex(const Vector3& pos) + : position(pos), normal(Vector3::ZERO) + { + positionData[0]=pos.x; + positionData[1]=pos.y; + positionData[2]=pos.z; + texcoord[0] = 0.; + texcoord[1] = 0.; + } + Vertex(const Vector3& pos, const Vector3& nor) + { + position=pos; + normal=nor; + } + Vector3 position; + Vector3 normal; + float positionData[3]; + float texcoord[2]; + }; + + + /** Represente un triangle via une liste de 3 indices. + */ + struct FaceIndex + { + FaceIndex() {}; + FaceIndex(int i0, int i1, int i2) + { + indexes[0] = i0; + indexes[1] = i1; + indexes[2] = i2; + }; + FaceIndex(const int* pIds) + { + indexes[0] = pIds[0]; + indexes[1] = pIds[1]; + indexes[2] = pIds[2]; + }; + unsigned int indexes[3]; + inline unsigned int& operator[] (int k) + { + assert(k<3); + return indexes[k]; + } + inline unsigned int operator[] (int k) const + { + assert(k<3); + return indexes[k]; + } + }; + /** Represente une liste de sommets + */ + typedef std::vector VertexArray; + + /** Represente une liste de triangles + */ + typedef std::vector FaceIndexArray; + + /** pour l'instant tous les sous-objets sont stockes sous la forme d'un seul gros objet + */ + VertexArray mVertices; + FaceIndexArray mFaces; + + bool hasNormals; + bool hasTextCoord; + bool useVBO; + + //VBO handlers + GLuint m_indexBuffer; + GLuint m_vertexBuffer; + GLuint m_normalBuffer; + GLuint m_texCoordBuffer; + +private: + QString fName; + double time; + void drawText(); + void createVBO(void); + bool Binfo; + Vector3 position; +}; +#endif diff --git a/src/ObjectView.cpp b/src/ObjectView.cpp new file mode 100644 index 0000000..197103f --- /dev/null +++ b/src/ObjectView.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + ***************************************************************************/ +#include "ObjectView.h" + +/* Ajout du BE */ +#include "Viewer.h" +#include "Scene.h" +#include "Light.h" +#include "Entity.h" +#include "Material.h" +#include "TextureLayer.h" +#include "Mesh.h" + +#include + +ObjectView::ObjectView() + : Q3MainWindow( 0, "Billboard Clouds - For Extreme Model Simplification", Qt::WDestructiveClose ) +{ + Q3PopupMenu * file = new Q3PopupMenu( this ); + menuBar()->insertItem( tr("&Fichier"), file ); + + file->insertItem( tr("&Quit"), qApp, SLOT( closeAllWindows() ), Qt::CTRL+Qt::Key_Q ); + + menuBar()->insertSeparator(); + + QGLFormat format; + format.setDoubleBuffer(true); + format.setDepth(true); + format.setRgba(true); + format.setAlpha(true); + format.setStencil(true); + format.setStereo(false); + QGLFormat::setDefaultFormat(format); + // glutInit(0, 0); + + mViewer = new Viewer( this, "glviewer" ); + mViewer->setFocus(); + setCentralWidget( mViewer ); + statusBar()->message(tr("Ready"), 2000); + + + connect(mViewer, SIGNAL(glInitialized()), this, SLOT(createScene())); + + mScene = new Scene(); + mViewer->attachScene(mScene); + +} + + +ObjectView::~ObjectView() +{ +} + +void ObjectView::createScene(void) +{ + Light *pLight; + pLight = new Light(Light::LT_POINT); + pLight->setPosition(Vector3(0., 0.,20.)); + pLight->setColor(Color(1.,1.,1.)); + mScene->add(pLight, false); +} + + +void ObjectView::load( const QString &fileName ) +{ + Entity *pEntity; + Transform t; + Material *pMat; + + QFile f( fileName ); + if ( !f.open( QIODevice::ReadOnly ) ) + return; + + pEntity = new Mesh(fileName, "obj"); + t.setIdentity(); + t.setPosition(0., 0., 0.); + //t.setOrientation(-90.,1.,0.,0.); + pEntity->setTransform(t); + pMat = new Material(); + pMat->setBaseColor(Color(0.8,0.6,0.5), 0.4); + pMat->setSpecular(Color::WHITE, 1); + pEntity->setMaterial(pMat); + mScene->remove(); + mScene->add(pEntity); + statusBar()->message( tr("Chargement de l'objet %1").arg(fileName), 2000 ); + mViewer->maj(); +} + +void ObjectView::load( const QString &fileName, const QString &textureName) +{ + Entity *pEntity; + Transform t; + Material *pMat; + TextureLayer* pLayer; + + QFile f( fileName ); + if ( !f.open( QIODevice::ReadOnly ) ) + return; + + pEntity = new Mesh(fileName, "obj"); + t.setIdentity(); + t.setPosition(0., 0., 0.); + //t.setOrientation(-90.,1.,0.,0.); + pEntity->setTransform(t); + pMat = new Material(); + pMat->setBaseColor(Color(0.8,0.6,0.5), 0.4); + pMat->setSpecular(Color::WHITE, 1); + + pLayer = new TextureLayer(textureName); + pMat->pushTextureLayer(pLayer); + + pEntity->setMaterial(pMat); + mScene->remove(); + mScene->add(pEntity); + statusBar()->message( tr("Chargement de l'objet %1").arg(fileName), 2000 ); + mViewer->maj(); +} diff --git a/src/OffScreenRendering.cpp b/src/OffScreenRendering.cpp new file mode 100644 index 0000000..84ac3e2 --- /dev/null +++ b/src/OffScreenRendering.cpp @@ -0,0 +1,411 @@ + +#define GLX_GLXEXT_PROTOTYPES +#include +#include +#include + +#include "OffScreenRendering.h" +#ifndef IRIX +#include +#include +using namespace std; +#else +#include +#include +#endif +// private Offscreen rendering data and methods + +const char* OffScreenRendering::_errorMessages[] = { + "OffScreenRendering : no error", + "OffScreenRendering : unsupported needed GL extensions", + "OffScreenRendering : couldn't get a valid X display", + "OffScreenRendering : missing GLX Pbuffer extension", + "OffScreenRendering : invalid parameters for pbuffer creation", + "OffScreenRendering : invalid off screen context", + "OffScreenRendering : Internal openGL Error, use glGetError() for more info", + "OffScreenRendering : glXMakeCurrent failed for offscreen rendering", + "OffScreenRendering : glXMakeCurrent failed for old context", + "OffScreenRendering : can't get XVisualInfo from FBconfig", + "OffScreenRendering : couldn't create GLXContext", + "OffScreenRendering : Unable to find an active context for sharing.", + "OffScreenRendering : realy, not yet implemented ~8-) !!! ", + None +}; + +int OffScreenRendering::OffScreenRenderingQueryForPbuffers(Display *dpy, int screen) +{ +#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) + char *extensions; + + extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS); + if (!strstr(extensions,"GLX_SGIX_fbconfig")) { + return 0; + } + if (!strstr(extensions,"GLX_SGIX_pbuffer")) { + return 0; + } + return 1; +#else +#error GLX_SGIX_fbconfig and GLX_SGIX_pbuffer not defined at compile time + return 0; +#endif +} + + +static int OffScreenRenderingXErrorFlag = 0; +static int OffScreenRenderingHandleXError( Display *dpy, XErrorEvent *event ) +{ + dpy=NULL; + event=NULL; + OffScreenRenderingXErrorFlag = 1; + return 0; +} + +#ifndef IRIX +GLXPbuffer OffScreenRendering::OffScreenRenderingCreatePbuffer( Display *dpy, GLXFBConfigSGIX fbConfig, int width, int height, int *pbAttribs ) +#else +GLXPbufferSGIX OffScreenRendering::OffScreenRenderingCreatePbuffer( Display *dpy, GLXFBConfigSGIX fbConfig, int width, int height, int *pbAttribs ) +#endif +{ + int (*oldHandler)( Display *, XErrorEvent * ); +#ifndef IRIX + GLXPbuffer pBuffer = None; +#else + GLXPbufferSGIX pBuffer = None; +#endif + + /* Catch X protocol errors with our own error handler */ + oldHandler = XSetErrorHandler( OffScreenRenderingHandleXError ); + + OffScreenRenderingXErrorFlag = 0; + + pBuffer = glXCreateGLXPbufferSGIX(dpy, fbConfig, width, height, pbAttribs); + + + /* Restore original X error handler */ + (void) XSetErrorHandler( oldHandler ); + + /* Return pbuffer (may be None) */ + if (!OffScreenRenderingXErrorFlag && pBuffer!=None) { + unsigned int w,h; +#ifndef IRIX + glXQueryGLXPbufferSGIX(dpy, pBuffer, GLX_WIDTH, &w); + glXQueryGLXPbufferSGIX(dpy, pBuffer, GLX_HEIGHT, &h); +#else + glXQueryGLXPbufferSGIX(dpy, pBuffer, GLX_WIDTH_SGIX, &w); + glXQueryGLXPbufferSGIX(dpy, pBuffer, GLX_HEIGHT_SGIX, &h); +#endif + return pBuffer; + } else { + return None; + } +} + + +#ifndef IRIX +GLXPbuffer OffScreenRendering::MakePbuffer( Display *dpy, int screen, int width, int height ) +#else +GLXPbufferSGIX OffScreenRendering::MakePbuffer( Display *dpy, int screen, int width, int height ) +#endif +{ + + int fbAttribs[100] = { + /* Single buffered, with depth buffer */ + GLX_RENDER_TYPE_SGIX, GLX_RGBA_BIT_SGIX, + GLX_DRAWABLE_TYPE_SGIX, GLX_PIXMAP_BIT_SGIX, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DOUBLEBUFFER, 0, + GLX_STENCIL_SIZE, 1, + None + }; + int pbAttribs[9] = { + GLX_LARGEST_PBUFFER_SGIX, True, + GLX_PRESERVED_CONTENTS_SGIX, False, +/* GLX_PBUFFER_WIDTH,0, + GLX_PBUFFER_HEIGHT,0,*/ + None + }; + /* Create the pbuffer using first fbConfig in the list that works. */ +// pbAttribs[5]=width+1; +// pbAttribs[7]=height; + + + GLXFBConfigSGIX *fbConfigs; +#ifndef IRIX + GLXPbuffer pBuffer = None; +#else + GLXPbufferSGIX pBuffer = None; +#endif + int nConfigs; + int i; + int redSize, greenSize, blueSize, alphaSize; + int depthSize, stencilSize; + + /* Get list of possible frame buffer configurations */ +#ifndef IRIX + fbConfigs = glXChooseFBConfig(dpy, screen, fbAttribs, &nConfigs); +#else + fbConfigs = glXChooseFBConfigSGIX(dpy, screen, fbAttribs, &nConfigs); +#endif + if (nConfigs==0 || !fbConfigs) { + return None; + } + +#ifdef IRIX +cerr << nConfigs << " compatible trouvees\n"; +#endif + for (i=0;i=8)&&(greenSize>=8)&&(blueSize>=8)&&(alphaSize>=8)&&(depthSize>=24)&&(stencilSize>=8)) { + pBuffer = OffScreenRendering::OffScreenRenderingCreatePbuffer(dpy, fbConfigs[i], width, height, pbAttribs); + if (pBuffer) { + _currentFBconfig = fbConfigs[i]; + break; + } + } + +#else + if ((redSize>=8)&&(greenSize>=8)&&(blueSize>=8)&&(alphaSize>=8)&&(depthSize>=24)&&(stencilSize>=8)) { + pBuffer = OffScreenRendering::OffScreenRenderingCreatePbuffer(dpy, fbConfigs[i], width, height, pbAttribs); + if (pBuffer) { + _currentFBconfig = fbConfigs[i]; + break; + } + } +#endif + } + + XFree(fbConfigs); + + return pBuffer; +} + + + +// Begin of OffScreenRendering callable method +OffScreenRendering::OffScreenRendering(int width,int height, bool share) : \ + _currentDisplay(0), _previousContext(0), _previousDrawable(0), _currentContext(0), \ + _currentPbuffer(0), _currentFBconfig(0), _validOffScreenRenderingObject(false), \ + _lastError(NO_ERROR), _inBlock(false),_width(width), _height(height) + +{ + if ((width < 1) || (height < 1)) { + _lastError=INVALID_PARAMETERS; + } else { + _currentDisplay=glXGetCurrentDisplay(); + if (_currentDisplay==NULL) { + _currentDisplay=XOpenDisplay(NULL); + } + if (!_currentDisplay) { + _lastError=MISSING_X_DISPLAY; + _validOffScreenRenderingObject=false; + } else { + if ( OffScreenRendering::OffScreenRenderingQueryForPbuffers(_currentDisplay,DefaultScreen(_currentDisplay)) ) { + _validOffScreenRenderingObject=true; + } else { + _lastError=PBUFFERS_UNAVAILABLE; + _validOffScreenRenderingObject=false; + } + } + if (_validOffScreenRenderingObject) + { + _currentPbuffer = MakePbuffer( _currentDisplay, DefaultScreen(_currentDisplay), _width, _height ); + if (_currentPbuffer!=None) + { +#ifndef IRIX + XVisualInfo *visInfo = glXGetVisualFromFBConfig(_currentDisplay, _currentFBconfig); +#else + XVisualInfo *visInfo = glXGetVisualFromFBConfigSGIX(_currentDisplay, _currentFBconfig); +#endif + if (!visInfo) { + _lastError=VISUAL_INFO_ERROR; + _validOffScreenRenderingObject=false; + } else { + if (share) { + GLXContext activeContext=glXGetCurrentContext (); + if (activeContext) { + _currentContext = glXCreateContext(_currentDisplay, visInfo, activeContext, True); + } else { + _lastError=NO_CUR_CTX_AVAILABLE; + _currentContext = glXCreateContext(_currentDisplay, visInfo, NULL, True); + } + } else { + _currentContext = glXCreateContext(_currentDisplay, visInfo, NULL, True); + } + if (!_currentContext) { + _lastError=CONTEXT_CREATION_ERROR; + _validOffScreenRenderingObject=false; + }else { + _validOffScreenRenderingObject=true; + } + XFree(visInfo); + } + } else { + _lastError=PBUFFERS_UNAVAILABLE; + _validOffScreenRenderingObject=false; + } + } + } +} + +OffScreenRendering::~OffScreenRendering() +{ + if (_validOffScreenRenderingObject) +#ifndef IRIX + glXDestroyPbuffer(_currentDisplay,_currentPbuffer); +#else + glXDestroyGLXPbufferSGIX(_currentDisplay,_currentPbuffer); +#endif +} + +OffScreenRendering::OffScreenRenderingError OffScreenRendering::begin() +{ + if (!_inBlock) { + if (_validOffScreenRenderingObject) { + _previousDrawable = glXGetCurrentDrawable(); + _previousContext = glXGetCurrentContext (); + if (!glXMakeCurrent (_currentDisplay, _currentPbuffer, _currentContext)) { + _lastError=ACTIVATE_FAIL; + } else { + _lastError=NO_ERROR; + _inBlock=true; + } + } else { + _lastError=INVALID_CONTEXT; + } + } else { + _lastError=BLOCK_ERROR; + } + return _lastError; +} + + +OffScreenRendering::OffScreenRenderingError OffScreenRendering::end() +{ + if (_inBlock) { + if (_validOffScreenRenderingObject) { + if (!glXMakeCurrent (_currentDisplay, _previousDrawable, _previousContext)) { + _lastError=DESACTIVATE_FAIL; + } else { + _lastError=NO_ERROR; + _inBlock=false; + } + } else { + _lastError=INVALID_CONTEXT; + } + } else { + _lastError=BLOCK_ERROR; + } + return _lastError; +} + +OffScreenRendering::OffScreenRenderingError OffScreenRendering::getError() const +{ + return _lastError; +} + + +const char *OffScreenRendering::getErrorMsg() const +{ + return _errorMessages[_lastError]; +} + +OffScreenRendering::OffScreenRenderingError OffScreenRendering::copyToTexture(unsigned int *gltextureObject, GLenum texture, GLenum target) +{ + if(!_validOffScreenRenderingObject) + { + _lastError=INVALID_CONTEXT; + return _lastError; + } + + if (!_inBlock) + { + begin(); + if (_lastError!=NO_ERROR) + return _lastError; + if (glIsTexture(*gltextureObject)) { + glBindTexture(texture, *gltextureObject); + } else { + unsigned char *theTexture = new unsigned char [_width*_height*3]; + glGenTextures( 1, gltextureObject ); + glBindTexture(texture, *gltextureObject); + glTexImage2D(target, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, theTexture); + delete []theTexture; + } + + glCopyTexSubImage2D( target, 0, 0, 0, 0, 0, _width, _height ); + _lastError=NO_ERROR; + + end(); + } + else + { + if (glIsTexture(*gltextureObject)) { + glBindTexture(texture, *gltextureObject); + } else { + unsigned char *theTexture = new unsigned char [_width*_height*3]; + glGenTextures( 1, gltextureObject ); + glBindTexture(texture, *gltextureObject); + glTexImage2D(target, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, theTexture); + delete []theTexture; + } + + glCopyTexSubImage2D( target, 0, 0, 0, 0, 0, _width, _height ); + _lastError=NO_ERROR; + } + return _lastError; +} + +OffScreenRendering::OffScreenRenderingError OffScreenRendering::copyToMemory(int x, int y, int width, int height, GLenum format, GLenum type, void *bufferOut) +{ + if (!_inBlock) { + if (_validOffScreenRenderingObject) { + begin(); + if (_lastError!=NO_ERROR) + return _lastError; + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(x, y, width, height, format, type, bufferOut); + _lastError = (glGetError() == GL_NO_ERROR) ? NO_ERROR : INTERNAL_OPENGL_ERROR; + if (_lastError!=NO_ERROR) + return _lastError; + end(); + } else { + _lastError=INVALID_CONTEXT; + } + } else { + _lastError=INVALID_OPERATION; + } + return _lastError; +} + +int OffScreenRendering::getWidth(void) +{ + return _width; +} + +int OffScreenRendering::getHeight(void) +{ + return _height; +} diff --git a/src/OffScreenRendering.h b/src/OffScreenRendering.h new file mode 100644 index 0000000..eb767aa --- /dev/null +++ b/src/OffScreenRendering.h @@ -0,0 +1,269 @@ +#ifndef __OFF_SCREEN_RENDERING__ +#define __OFF_SCREEN_RENDERING__ +#include +#include + +/** Off screen rendering class. OffScreenRendering + + This class is designed to make off screen rendering method transparent to the user. + + See the provided offscreendemo.cpp source file to have informations about using it. + @version 0.1 + @author Mathias Paulin - IRIT-UPS-CNRS + @date January 2002 + @todo Things that remains to verify or develop. + @todo Verify robustness of the class. + @todo Port to windows. + @todo Test under IRIX. + + \nosubgrouping + +*/ + +/* + 17/10/2003 - Gael - new methods : getWidth() and getHeight() + 09/11/2005 - Gael - It is now allowed to use the copyToTexture method inside a block begin/end +*/ + +class OffScreenRendering { + // static private method and attributes + private : + static const char* _errorMessages[]; + static int OffScreenRenderingQueryForPbuffers(Display *dpy, int screen); +#ifndef IRIX + static GLXPbuffer OffScreenRenderingCreatePbuffer( Display *dpy, GLXFBConfigSGIX fbConfig, int width, int height, int *pbAttribs ); +#else + static GLXPbufferSGIX OffScreenRenderingCreatePbuffer( Display *dpy, GLXFBConfigSGIX fbConfig, int width, int height, int *pbAttribs ); +#endif + // public inner enumeration for error handling + public : + /** @name Error management. + \anchor ErrorGroup + Error management types and methods. + Error management works as follow : + - methods never stops the calling programm, even in case of error + - methods set the last error code on the state machine + - the caller must ensure that no error occurs after a call to a method + */ + /*@{*/ + /** This enum indicates the error number of the last off screen rendering command. + The values could be returned bye the function \ref getError () . + To obtain a human readable description of this error, call \ref getErrorMsg () . + */ + enum OffScreenRenderingError { + NO_ERROR = 0, /*!< OffScreenRendering : no error. */ + MISSING_GL_EXTENSIONS, /*!< OffScreenRendering : unsupported needed GL extensions. */ + MISSING_X_DISPLAY, /*!< OffScreenRendering : couldn't get a valid X display. */ + PBUFFERS_UNAVAILABLE, /*!< OffScreenRendering : missing GLX Pbuffer extension. */ + INVALID_PARAMETERS, /*!< OffScreenRendering : invalid parameters for pbuffer creation. */ + INVALID_CONTEXT, /*!< OffScreenRendering : invalid off screen context. */ + INTERNAL_OPENGL_ERROR, /*!< OffScreenRendering : Internal openGL Error, use glGetError() for more info. */ + ACTIVATE_FAIL, /*!< OffScreenRendering : glXMakeCurrent failed for offscreen rendering. */ + DESACTIVATE_FAIL, /*!< OffScreenRendering : glXMakeCurrent failed for old context. */ + VISUAL_INFO_ERROR, /*!< OffScreenRendering : can't get XVisualInfo from FBconfig. */ + CONTEXT_CREATION_ERROR, /*!< OffScreenRendering : couldn't create GLXContext */ + NO_CUR_CTX_AVAILABLE, /*!< OffScreenRendering : Unable to find an active context for sharing. */ + INVALID_OPERATION, /*!< OffScreenRendering : Calling of a non authorized method beetween begin() and end(). */ + BLOCK_ERROR, /*!< OffScreenRendering : Wrong begin() - end() structure. */ + NOT_YET_IMPLEMENTED, /*!< OffScreenRendering : really, not yet implemented ~8-) !!! */ + }; + + /** Gets the last error code. + \anchor getError + @return error code. Use \ref getErrorMsg () to have more informations + \sa \ref ErrorGroup "Error management" + */ + OffScreenRenderingError getError() const; + + /** Gets the last error message. + \anchor getErrorMsg + @return error message build from the last \ref ErrorGroup "Error management". + */ + const char *getErrorMsg() const; + + /*@}*/ + + // private data and member methods + private : + // For X connection + Display *_currentDisplay; + + /** @name Context switching management attributes. + These attributes are used for management of rendering context switching. + Each attribute is set when calling \ref begin () and used whe calling \ref end () to restore the previous + rendering context. + */ + /*@{*/ + + /** the active rendering context before activation of the off screen rendering context. + */ + GLXContext _previousContext; + + /** the active drawable context before activation of the off screen rendering context. + */ + GLXDrawable _previousDrawable; + + /*@}*/ + + /** @name Off screen Context related attributes. + These attributes are used for management of rendering context switching. + Each attribute is initialized in the constructor and used when calling \ref begin () set the off screen + rendering context. + */ + /*@{*/ + /** The "real" off screen rendering context. + */ + GLXContext _currentContext; + /** The drawable for offscreen rendering (a p-buffer). + */ +#ifndef IRIX + GLXPbuffer _currentPbuffer; +#else + GLXPbufferSGIX _currentPbuffer; +#endif + /** The frame buffer config for the offscreen rendering context. + */ + GLXFBConfigSGIX _currentFBconfig; + + /*@}*/ + + /** @name Internal state variable attributes. + These attributes are used for error management and internal state checking. + */ + /*@{*/ + + /** Indicates if the off screen context is usable. + */ + bool _validOffScreenRenderingObject; + + /** The last occured internal error. + \sa \ref ErrorGroup "Error management" + */ + OffScreenRenderingError _lastError; + + /** begin() - end() strucutre state. + */ + bool _inBlock; + + /** Width of the PBuffer. + */ + int _width; + + /** Height of the PBuffer. + */ + int _height; + + /*@}*/ + + // Initialisation of the PBuffer +#ifndef IRIX + GLXPbuffer MakePbuffer( Display *dpy, int screen, int width, int height ); +#else + GLXPbufferSGIX MakePbuffer( Display *dpy, int screen, int width, int height ); +#endif + + // public member methods + public : + /** @name Constructor and destructor. + */ + /*@{*/ + /** OffScreenRendering : create an offscreen rendering context through the allocation of a pbuffer. + Use \ref getErrorMsg () to have informations about the created (or not) rendering context. + + The created OffScreenRendering context has the following properties : + Single buffered. + Size given by width and height parameters. + RGBA has 8888 bits. + Stencil has 8 bits. + Depth has 24 bits. + + @param width width of the offscreen rendering context + @param height height of the offscreen rendering context + @param share indicate if we must share display_lists and textures with the current rendering context + + @todo Make off screen context parameters modifiable (Color depth, Number of buffer ...). + @bug There is no verification of the upper limit in the size required by the user. + May kill the X-Server if the size is too high. + */ + OffScreenRendering(int width=256,int height=256, bool share=false); + + /** Destroy the OffScreenRendering context. + */ + ~OffScreenRendering(); + /*@}*/ + + /** @name Context switching methods. + */ + /*@{*/ + + /** Activate the OffScreenRendering context. + \anchor begin + When an OffScreenRendering context is activated, all the subsequents calls to OpenGL functions + implie that the target rendering context is this OffScreenRendering context. + + @return error code. Use \ref getErrorMsg () to have more informations. + */ + OffScreenRenderingError begin(); + + /** Desactivate the OffScreenRendering context. + \anchor end + When an OffScreenRendering context is desactivated, the old rendering context, obtained when begin was + called is restore. + + @return error code. Use \ref getErrorMsg () to have more informations. + */ + OffScreenRenderingError end(); + /*@}*/ + + /** @name Data extraction methods. + */ + /*@{*/ + /** Copy the content of the colorBuffer from the OffScreenRendering context to the gltextureObject. + + When this function is called, it first verify if the gltextureObject is a valid one. + If true, the assumption that texture size matches pbuffer size is made. If assumption fails, + may kill the X Server. + If gltextureObject is valid, moves the color buffer content to this texture object as + level-of-detail number 0. + If gltextureObject is valid, eventually deletes this texture object and allocate a new + one with the content of the pbuffer as pixel. + + Note that this method does not alter the current rendering context neither the content of the + OffScreenRendering buffers. + + @param gltextureObject : the texture object to use or create; + @return error code. Use \ref getErrorMsg () to have more informations. + */ + OffScreenRenderingError copyToTexture(unsigned int *gltextureObject, GLenum texture=GL_TEXTURE_2D,GLenum target=GL_TEXTURE_2D); + + /** Copy the content of the specified buffer to provided buffer. + + @param x, y Specify the window coordinates of the first pixel that + is read from the frame buffer. This location is the + lower left corner of a rectangular block of pixels. + @param width, height + Specify the dimensions of the pixel rectangle. width + and height of one correspond to a single pixel. + @param format + Specifies the format of the pixel data. The following + symbolic values are accepted: GL_COLOR_INDEX, + GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_RED, GL_GREEN, + GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, and + GL_LUMINANCE_ALPHA. + @param type Specifies the data type of the pixel data. Must be one + of GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, + GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, + or GL_FLOAT. + @param bufferOut + Returns the pixel data. + @return error code. Use \ref getErrorMsg () to have more informations. + */ + OffScreenRenderingError copyToMemory(int x, int y, int width, int height, GLenum format, GLenum type, void *bufferOut); + + int getWidth(void); + int getHeight(void); + /*@}*/ + + +}; +#endif diff --git a/src/OpenGL.h b/src/OpenGL.h new file mode 100644 index 0000000..dd096ca --- /dev/null +++ b/src/OpenGL.h @@ -0,0 +1,58 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + + +#ifndef _OpenGL_h_ +#define _OpenGL_h_ + +#include +// disable auto-include of the glext.h file +#define GL_GLEXT_LEGACY 1 + +//#include + +// get the definition of all extension functions +#define GL_GLEXT_PROTOTYPES 1 + +#ifndef GLAPI +// the glext.h nvidia file contains some bugs, so : +#define GLAPI APIENTRY +#endif + +#ifndef GL_EXT_blend_equation_separate +#define GL_EXT_blend_equation_separate 1 +#ifdef GL_GLEXT_PROTOTYPES +extern void glBlendEquationSeparateEXT (GLenum, GLenum); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (* PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); +#endif + + +#include + +#include + + +#define _SUPPORT_GLSLANG_ +#define _SUPPORT_STENCIL_TWO_SIDE_ + + +#ifdef DEBUG + #define GL_TEST_ERR\ + {\ + GLenum eCode;\ + if((eCode=glGetError())!=GL_NO_ERROR)\ + std::cerr << "OpenGL error : " << gluErrorString(eCode) << " in " << __FILE__ << " : " << __LINE__ << std::endl;\ + } +#else + #define GL_TEST_ERR +#endif + + +#endif + + diff --git a/src/Plane.cpp b/src/Plane.cpp new file mode 100644 index 0000000..cc00136 --- /dev/null +++ b/src/Plane.cpp @@ -0,0 +1,101 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Plane.h" +#include "Material.h" + +//#include "OpenGL.h" + +Plane::Plane(int gridSizeX, int gridSizeY,const QString& name) + : Entity(name) +{ + initialiaze(gridSizeX,gridSizeY); +} +Plane::Plane(const QString& name) + : Entity(name) +{ + initialiaze(1,1); +} +void Plane::initialiaze(int gridSizeX, int gridSizeY) +{ + mSizeX = gridSizeX; + mSizeY = gridSizeY; + gridSizeX++; + gridSizeY++; + mVertices = new Vector3[gridSizeX*gridSizeY]; + mIndexes = new GLuint[(gridSizeX-1)*(gridSizeY-1)*4]; // 1 face = 1 quad = 4 sommets par face ! + + // compute vertex + for(int j=0 ; jgetNumberOfLayers() ; ++i) + { + glClientActiveTexture(GL_TEXTURE0+i); + glTexCoordPointer(2, GL_FLOAT, sizeof(Vector3), mVertices); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + // set the normales for all vertex + glNormal3f(0., 0., 1.); + glDrawElements(GL_QUADS, mSizeX*mSizeY*4, GL_UNSIGNED_INT, mIndexes); + glDisableClientState(GL_VERTEX_ARRAY); + + for(int i=0 ; igetNumberOfLayers() ; ++i) + { + glClientActiveTexture(GL_TEXTURE0+i); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + glClientActiveTexture(GL_TEXTURE0); + /*******************************************************************/ + /* Fin code à faire/completer par l'étudiant */ + /* Texture */ + /*******************************************************************/ +} +//-------------------------------------------------------------------------------- +void Plane::getEquation(double eq[4]) const +{ + Vector3 n(0., 0. , 1.); + n = mTransform.getOrientation() * n; + n.normalise(); + eq[0]=n.x; eq[1]=n.y; eq[2]=n.z; + eq[3] = -n.dotProduct(mTransform.getPosition()); +} + diff --git a/src/Plane.h b/src/Plane.h new file mode 100644 index 0000000..73eaa0a --- /dev/null +++ b/src/Plane.h @@ -0,0 +1,45 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Plane_h_ +#define _Plane_h_ + +#include "Entity.h" + +/** Représente un plan unitaire dans le plan xy et centré en (0.5, 0.5, 0). + Le plan est en faite tracé sous la forme d'une grille. +*/ +class Plane : public Entity +{ +public: + /** Consructeur. + \param nbQuadX nombre de subdivision selon l'axe des X + \param nbQuadY nombre de subdivision selon l'axe des Y + */ + Plane(int nbQuadX, int nbQuadY, const QString& name = ""); + + Plane(const QString& name = ""); + + void getEquation(double eq[4]) const; + +protected: + + void initialiaze(int nbQuadX, int nbQuadY); + + /** Tracé de la grille (du plan). + Le tracé utilise les vertex array. + \note à  compléter par l'étudiant (texture) + */ + virtual void drawGeometry(void); + + Vector3 *mVertices; + unsigned int *mIndexes; + int mSizeX, mSizeY; + +}; + +#endif diff --git a/src/Quaternion.cpp b/src/Quaternion.cpp new file mode 100644 index 0000000..125e813 --- /dev/null +++ b/src/Quaternion.cpp @@ -0,0 +1,460 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +// NOTE THAT THIS FILE IS BASED ON MATERIAL FROM: + +// Magic Software, Inc. +// http://www.magic-software.com +// Copyright (c) 2000, All Rights Reserved +// +// Source code from Magic Software is supplied under the terms of a license +// agreement and may not be copied or disclosed except in accordance with the +// terms of that agreement. The various license agreements may be found at +// the Magic Software web site. This file is subject to the license +// +// FREE SOURCE CODE +// http://www.magic-software.com/License/free.pdf + +#include "Quaternion.h" + +#include +#include "Matrix3.h" +#include "Vector3.h" + + +const float Quaternion::ms_fEpsilon = 1e-03; +const Quaternion Quaternion::ZERO(0.0,0.0,0.0,0.0); +const Quaternion Quaternion::IDENTITY(1.0,0.0,0.0,0.0); + +//----------------------------------------------------------------------- +Quaternion::Quaternion (float fW, float fX, float fY, float fZ) +{ + w = fW; + x = fX; + y = fY; + z = fZ; +} +//----------------------------------------------------------------------- +Quaternion::Quaternion (const Quaternion& rkQ) +{ + w = rkQ.w; + x = rkQ.x; + y = rkQ.y; + z = rkQ.z; +} +//----------------------------------------------------------------------- +void Quaternion::FromRotationMatrix (const Matrix3& kRot) +{ + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + + float fTrace = kRot[0][0]+kRot[1][1]+kRot[2][2]; + float fRoot; + + if ( fTrace > 0.0 ) + { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = sqrt(fTrace + 1.0); // 2w + w = 0.5*fRoot; + fRoot = 0.5/fRoot; // 1/(4w) + x = (kRot[2][1]-kRot[1][2])*fRoot; + y = (kRot[0][2]-kRot[2][0])*fRoot; + z = (kRot[1][0]-kRot[0][1])*fRoot; + } + else + { + // |w| <= 1/2 + static int s_iNext[3] = { 1, 2, 0 }; + int i = 0; + if ( kRot[1][1] > kRot[0][0] ) + i = 1; + if ( kRot[2][2] > kRot[i][i] ) + i = 2; + int j = s_iNext[i]; + int k = s_iNext[j]; + + fRoot = sqrt(kRot[i][i]-kRot[j][j]-kRot[k][k] + 1.0); + float* apkQuat[3] = { &x, &y, &z }; + *apkQuat[i] = 0.5*fRoot; + fRoot = 0.5/fRoot; + w = (kRot[k][j]-kRot[j][k])*fRoot; + *apkQuat[j] = (kRot[j][i]+kRot[i][j])*fRoot; + *apkQuat[k] = (kRot[k][i]+kRot[i][k])*fRoot; + } +} +//----------------------------------------------------------------------- +void Quaternion::ToRotationMatrix (Matrix3& kRot) const +{ + float fTx = 2.0*x; + float fTy = 2.0*y; + float fTz = 2.0*z; + float fTwx = fTx*w; + float fTwy = fTy*w; + float fTwz = fTz*w; + float fTxx = fTx*x; + float fTxy = fTy*x; + float fTxz = fTz*x; + float fTyy = fTy*y; + float fTyz = fTz*y; + float fTzz = fTz*z; + + kRot[0][0] = 1.0-(fTyy+fTzz); + kRot[0][1] = fTxy-fTwz; + kRot[0][2] = fTxz+fTwy; + kRot[1][0] = fTxy+fTwz; + kRot[1][1] = 1.0-(fTxx+fTzz); + kRot[1][2] = fTyz-fTwx; + kRot[2][0] = fTxz-fTwy; + kRot[2][1] = fTyz+fTwx; + kRot[2][2] = 1.0-(fTxx+fTyy); +} +//----------------------------------------------------------------------- +void Quaternion::FromAngleAxis (const float& rfAngle, + const Vector3& rkAxis) +{ + // assert: axis[] is unit length + // + // The quaternion representing the rotation is + // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k) + + float fHalfAngle = 0.5*rfAngle; + float fSin = sin(fHalfAngle); + w = cos(fHalfAngle); + x = fSin*rkAxis.x; + y = fSin*rkAxis.y; + z = fSin*rkAxis.z; +} +//----------------------------------------------------------------------- +void Quaternion::ToAngleAxis (float& rfAngle, Vector3& rkAxis) const +{ + // The quaternion representing the rotation is + // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k) + + float fSqrLength = x*x+y*y+z*z; + if ( fSqrLength > 0.0 ) + { + rfAngle = 2.0*acos(w); + float fInvLength = 1.0/sqrt(fSqrLength); + rkAxis.x = x*fInvLength; + rkAxis.y = y*fInvLength; + rkAxis.z = z*fInvLength; + } + else + { + // angle is 0 (mod 2*pi), so any axis will do + rfAngle = 0.0; + rkAxis.x = 1.0; + rkAxis.y = 0.0; + rkAxis.z = 0.0; + } +} +//----------------------------------------------------------------------- +void Quaternion::FromAxes (const Vector3* akAxis) +{ + Matrix3 kRot; + + for (int iCol = 0; iCol < 3; iCol++) + { + kRot[0][iCol] = akAxis[iCol].x; + kRot[1][iCol] = akAxis[iCol].y; + kRot[2][iCol] = akAxis[iCol].z; + } + + FromRotationMatrix(kRot); +} +//----------------------------------------------------------------------- +void Quaternion::FromAxes (const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis) +{ + Matrix3 kRot; + + kRot[0][0] = xAxis.x; + kRot[1][0] = xAxis.y; + kRot[2][0] = xAxis.z; + + kRot[0][1] = yAxis.x; + kRot[1][1] = yAxis.y; + kRot[2][1] = yAxis.z; + + kRot[0][2] = zAxis.x; + kRot[1][2] = zAxis.y; + kRot[2][2] = zAxis.z; + + FromRotationMatrix(kRot); + +} +//----------------------------------------------------------------------- +void Quaternion::ToAxes (Vector3* akAxis) const +{ + Matrix3 kRot; + + ToRotationMatrix(kRot); + + for (int iCol = 0; iCol < 3; iCol++) + { + akAxis[iCol].x = kRot[0][iCol]; + akAxis[iCol].y = kRot[1][iCol]; + akAxis[iCol].z = kRot[2][iCol]; + } +} +//----------------------------------------------------------------------- +void Quaternion::ToAxes (Vector3& xAxis, Vector3& yAxis, Vector3& zAxis) const +{ + Matrix3 kRot; + + ToRotationMatrix(kRot); + + xAxis.x = kRot[0][0]; + xAxis.y = kRot[1][0]; + xAxis.z = kRot[2][0]; + + yAxis.x = kRot[0][1]; + yAxis.y = kRot[1][1]; + yAxis.z = kRot[2][1]; + + zAxis.x = kRot[0][2]; + zAxis.y = kRot[1][2]; + zAxis.z = kRot[2][2]; +} + +//----------------------------------------------------------------------- +Quaternion& Quaternion::operator= (const Quaternion& rkQ) +{ + w = rkQ.w; + x = rkQ.x; + y = rkQ.y; + z = rkQ.z; + return *this; +} +//----------------------------------------------------------------------- +Quaternion Quaternion::operator+ (const Quaternion& rkQ) const +{ + return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z); +} +//----------------------------------------------------------------------- +Quaternion Quaternion::operator- (const Quaternion& rkQ) const +{ + return Quaternion(w-rkQ.w,x-rkQ.x,y-rkQ.y,z-rkQ.z); +} +//----------------------------------------------------------------------- +Quaternion Quaternion::operator* (const Quaternion& rkQ) const +{ + // NOTE: Multiplication is not generally commutative, so in most + // cases p*q != q*p. + + return Quaternion + ( + w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z, + w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y, + w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z, + w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x + ); +} +//----------------------------------------------------------------------- +Quaternion Quaternion::operator* (float fScalar) const +{ + return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z); +} +//----------------------------------------------------------------------- +Quaternion operator* (float fScalar, const Quaternion& rkQ) +{ + return Quaternion(fScalar*rkQ.w,fScalar*rkQ.x,fScalar*rkQ.y, + fScalar*rkQ.z); +} +//----------------------------------------------------------------------- +Quaternion Quaternion::operator- () const +{ + return Quaternion(-w,-x,-y,-z); +} +//----------------------------------------------------------------------- +float Quaternion::Dot (const Quaternion& rkQ) const +{ + return w*rkQ.w+x*rkQ.x+y*rkQ.y+z*rkQ.z; +} +//----------------------------------------------------------------------- +float Quaternion::Norm () const +{ + return w*w+x*x+y*y+z*z; +} +//----------------------------------------------------------------------- +Quaternion Quaternion::Inverse () const +{ + float fNorm = w*w+x*x+y*y+z*z; + if ( fNorm > 0.0 ) + { + float fInvNorm = 1.0/fNorm; + return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm); + } + else + { + // return an invalid result to flag the error + return ZERO; + } +} +//----------------------------------------------------------------------- +Quaternion Quaternion::UnitInverse () const +{ + // assert: 'this' is unit length + return Quaternion(w,-x,-y,-z); +} +//----------------------------------------------------------------------- +Quaternion Quaternion::Exp () const +{ + // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then + // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero, + // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1. + + float fAngle = sqrt(x*x+y*y+z*z); + float fSin = sin(fAngle); + + Quaternion kResult; + kResult.w = cos(fAngle); + + if ( fabs(fSin) >= ms_fEpsilon ) + { + float fCoeff = fSin/fAngle; + kResult.x = fCoeff*x; + kResult.y = fCoeff*y; + kResult.z = fCoeff*z; + } + else + { + kResult.x = x; + kResult.y = y; + kResult.z = z; + } + + return kResult; +} +//----------------------------------------------------------------------- +Quaternion Quaternion::Log () const +{ + // If q = cos(A)+sin(A)*(x*i+y*j+z*k) where (x,y,z) is unit length, then + // log(q) = A*(x*i+y*j+z*k). If sin(A) is near zero, use log(q) = + // sin(A)*(x*i+y*j+z*k) since sin(A)/A has limit 1. + + Quaternion kResult; + kResult.w = 0.0; + + if ( fabs(w) < 1.0 ) + { + float fAngle = acos(w); + float fSin = sin(fAngle); + if ( fabs(fSin) >= ms_fEpsilon ) + { + float fCoeff = fAngle/fSin; + kResult.x = fCoeff*x; + kResult.y = fCoeff*y; + kResult.z = fCoeff*z; + return kResult; + } + } + + kResult.x = x; + kResult.y = y; + kResult.z = z; + + return kResult; +} +//----------------------------------------------------------------------- +Vector3 Quaternion::operator* (const Vector3& v) const +{ + // nVidia SDK implementation + Vector3 uv, uuv; + Vector3 qvec(x, y, z); + uv = qvec.crossProduct(v); + uuv = qvec.crossProduct(uv); + uv *= (2.0f * w); + uuv *= 2.0f; + + return v + uv + uuv; + +} +//----------------------------------------------------------------------- +Quaternion Quaternion::Slerp (float fT, const Quaternion& rkP, + const Quaternion& rkQ) +{ + float fCos = rkP.Dot(rkQ); + float fAngle = acos(fCos); + + if ( fabs(fAngle) < ms_fEpsilon ) + return rkP; + + float fSin = sin(fAngle); + float fInvSin = 1.0/fSin; + float fCoeff0 = sin((1.0-fT)*fAngle)*fInvSin; + float fCoeff1 = sin(fT*fAngle)*fInvSin; + return fCoeff0*rkP + fCoeff1*rkQ; +} +//----------------------------------------------------------------------- +Quaternion Quaternion::SlerpExtraSpins (float fT, + const Quaternion& rkP, const Quaternion& rkQ, int iExtraSpins) +{ + float fCos = rkP.Dot(rkQ); + float fAngle = acos(fCos); + + if ( fabs(fAngle) < ms_fEpsilon ) + return rkP; + + float fSin = sin(fAngle); + float fPhase = M_PI*iExtraSpins*fT; + float fInvSin = 1.0/fSin; + float fCoeff0 = sin((1.0-fT)*fAngle - fPhase)*fInvSin; + float fCoeff1 = sin(fT*fAngle + fPhase)*fInvSin; + return fCoeff0*rkP + fCoeff1*rkQ; +} +//----------------------------------------------------------------------- +void Quaternion::Intermediate (const Quaternion& rkQ0, + const Quaternion& rkQ1, const Quaternion& rkQ2, + Quaternion& rkA, Quaternion& rkB) +{ + // assert: q0, q1, q2 are unit quaternions + + Quaternion kQ0inv = rkQ0.UnitInverse(); + Quaternion kQ1inv = rkQ1.UnitInverse(); + Quaternion rkP0 = kQ0inv*rkQ1; + Quaternion rkP1 = kQ1inv*rkQ2; + Quaternion kArg = 0.25*(rkP0.Log()-rkP1.Log()); + Quaternion kMinusArg = -kArg; + + rkA = rkQ1*kArg.Exp(); + rkB = rkQ1*kMinusArg.Exp(); +} +//----------------------------------------------------------------------- +Quaternion Quaternion::Squad (float fT, + const Quaternion& rkP, const Quaternion& rkA, + const Quaternion& rkB, const Quaternion& rkQ) +{ + float fSlerpT = 2.0*fT*(1.0-fT); + Quaternion kSlerpP = Slerp(fT,rkP,rkQ); + Quaternion kSlerpQ = Slerp(fT,rkA,rkB); + return Slerp(fSlerpT,kSlerpP,kSlerpQ); +} +//----------------------------------------------------------------------- +bool Quaternion::operator== (const Quaternion& rhs) const +{ + return (rhs.x == x) && (rhs.y == y) && + (rhs.z == z) && (rhs.w == w); +} + + diff --git a/src/Quaternion.h b/src/Quaternion.h new file mode 100644 index 0000000..b27be26 --- /dev/null +++ b/src/Quaternion.h @@ -0,0 +1,126 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +// NOTE THAT THIS FILE IS BASED ON MATERIAL FROM: + +// Magic Software, Inc. +// http://www.magic-software.com +// Copyright (c) 2000, All Rights Reserved +// +// Source code from Magic Software is supplied under the terms of a license +// agreement and may not be copied or disclosed except in accordance with the +// terms of that agreement. The various license agreements may be found at +// the Magic Software web site. This file is subject to the license +// +// FREE SOURCE CODE +// http://www.magic-software.com/License/free.pdf + +#ifndef __Quaternion_H__ +#define __Quaternion_H__ + +#include + +class Vector3; +class Matrix3; + +/** Implementation of a Quaternion, i.e. a rotation around an axis. +*/ +class Quaternion +{ +public: + Quaternion ( + float fW = 1.0, + float fX = 0.0, float fY = 0.0, float fZ = 0.0); + Quaternion (const Quaternion& rkQ); + + void FromRotationMatrix (const Matrix3& kRot); + void ToRotationMatrix (Matrix3& kRot) const; + void FromAngleAxis (const float& rfAngle, const Vector3& rkAxis); + void ToAngleAxis (float& rfAngle, Vector3& rkAxis) const; + void FromAxes (const Vector3* akAxis); + void FromAxes (const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis); + void ToAxes (Vector3* akAxis) const; + void ToAxes (Vector3& xAxis, Vector3& yAxis, Vector3& zAxis) const; + + Quaternion& operator= (const Quaternion& rkQ); + Quaternion operator+ (const Quaternion& rkQ) const; + Quaternion operator- (const Quaternion& rkQ) const; + Quaternion operator* (const Quaternion& rkQ) const; + Quaternion operator* (float fScalar) const; + friend Quaternion operator* (float fScalar, + const Quaternion& rkQ); + Quaternion operator- () const; + bool operator== (const Quaternion& rhs) const; + + // functions of a quaternion + float Dot (const Quaternion& rkQ) const; // dot product + float Norm () const; // squared-length + Quaternion Inverse () const; // apply to non-zero quaternion + Quaternion UnitInverse () const; // apply to unit-length quaternion + Quaternion Exp () const; + Quaternion Log () const; + + // rotation of a vector by a quaternion + Vector3 operator* (const Vector3& rkVector) const; + + // spherical linear interpolation + static Quaternion Slerp (float fT, const Quaternion& rkP, + const Quaternion& rkQ); + + static Quaternion SlerpExtraSpins (float fT, + const Quaternion& rkP, const Quaternion& rkQ, + int iExtraSpins); + + // setup for spherical quadratic interpolation + static void Intermediate (const Quaternion& rkQ0, + const Quaternion& rkQ1, const Quaternion& rkQ2, + Quaternion& rka, Quaternion& rkB); + + // spherical quadratic interpolation + static Quaternion Squad (float fT, const Quaternion& rkP, + const Quaternion& rkA, const Quaternion& rkB, + const Quaternion& rkQ); + + // cutoff for sine near zero + static const float ms_fEpsilon; + + // special values + static const Quaternion ZERO; + static const Quaternion IDENTITY; + + float w, x, y, z; + + /** Function for writing to a stream. + */ + inline friend std::ostream& operator << + ( std::ostream& o, const Quaternion& q ) + { + o << "[" << q.x << ", " << q.y << ", " << q.z << ", " << q.w << "]"; + return o; + } + +}; + + +#endif diff --git a/src/Scene.cpp b/src/Scene.cpp new file mode 100644 index 0000000..f515658 --- /dev/null +++ b/src/Scene.cpp @@ -0,0 +1,233 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Scene.h" +#include "ShadowMap.h" + + +Scene::Scene() + : mAmbient(0.4,0.4,0.4), mShadowMap(0), mShadowEnabled(false),textureEnable(false) +{ +} +//-------------------------------------------------------------------------------- +Scene::~Scene() +{ + for(EntityMap::iterator it=mAllEntities.begin() ; it!=mAllEntities.end() ; ++it) + { + delete it->second; + } +} +//-------------------------------------------------------------------------------- +bool Scene::isShadowEnabled(void) const +{ + return mShadowEnabled; +} +void Scene::setShadowEnabled(bool on) +{ + mShadowEnabled = on; + if(mShadowEnabled && ! mShadowMap) + { + mShadowMap = new ShadowMap; + } +} +//-------------------------------------------------------------------------------- +void Scene::setAmbient(const Color& c) +{ + mAmbient = c; +} +const Color& Scene::getAmbient(void) const +{ + return mAmbient; +} +//-------------------------------------------------------------------------------- +void Scene::add(Entity* pObj, bool castShadow /*=true*/) +{ + mAllEntities[pObj->getName()] = pObj; + mEntities.push_back(EntityElement(pObj,castShadow)); +} + +void Scene::remove(bool delMesh){ + if (mEntities.size()!=0) + { + if(delMesh) delete mEntities[0].pEntity; + while(mEntities.size()!=0) mEntities.pop_back(); + } +} +//-------------------------------------------------------------------------------- +void Scene::add(Light* pLight, bool castShadow /*=false*/) +{ + mAllEntities[pLight->getName()] = pLight; + mLights.push_back(LightElement(pLight,castShadow)); +} +//-------------------------------------------------------------------------------- +Entity* Scene::getByName(const QString& name) +{ + EntityMap::const_iterator entity_iter = mAllEntities.find(name); + if(entity_iter!=mAllEntities.end()) + { + return entity_iter->second; + } + + return 0; +} +//-------------------------------------------------------------------------------- +void Scene::activateLights(void) +{ + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, mAmbient); + + int lightNum = 0; + for(LightList::iterator it=mLights.begin() ; it!=mLights.end() ; ++it) + { + it->pLight->activate(lightNum++); + } +} +//-------------------------------------------------------------------------------- +void Scene::releaseLights(void) +{ + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Color::BLACK); + for(LightList::iterator it=mLights.begin() ; it!=mLights.end() ; ++it) + { + it->pLight->release(); + } +} +//-------------------------------------------------------------------------------- +void Scene::renderObjects(bool activateMaterial /*= true*/) +{ + for(EntityList::iterator it=mEntities.begin() ; it!=mEntities.end() ; ++it) + { + it->pEntity->render(activateMaterial); + } +} +//-------------------------------------------------------------------------------- +void Scene::renderOccluders(bool activateMaterial /*= false*/) +{ + for(EntityList::iterator it=mEntities.begin() ; it!=mEntities.end() ; ++it) + { + if(it->castShadow) + it->pEntity->render(activateMaterial); + } +} +//-------------------------------------------------------------------------------- +void Scene::render(void) +{ + if(mShadowEnabled) + { + // recherche de la premiere source devant generer des ombres portees + Light* pLight4Shadow = 0; + for(LightList::iterator it=mLights.begin() ; it!=mLights.end() ; ++it) + { + if(it->castShadow) + { + pLight4Shadow = it->pLight; + it = mLights.end(); + it--; + } + } + if(pLight4Shadow) + { + /*******************************************************************/ + /* Debut code a faire/completer par l'etudiant */ + /* shadow map */ + /*******************************************************************/ + + // a faire : mise a jour de la shadow map et rendu de la scene avec la shadow map + + // mise a jour de la shadow map + mShadowMap->setLight(pLight4Shadow); + mShadowMap->beginUpdate(); + renderOccluders(); + mShadowMap->endUpdate(); + + // rendu de la scene avec la shadow map + activateLights(); + mShadowMap->activate(); + renderObjects(); + mShadowMap->release(); + releaseLights(); + /*******************************************************************/ + /* Fin code a faire/completer par l'etudiant */ + /* shadow map */ + /*******************************************************************/ + } + else + { + activateLights(); + renderObjects(); + releaseLights(); + } + } + else + { + activateLights(); + renderObjects(); + releaseLights(); + } + + for(LightList::iterator it=mLights.begin() ; it!=mLights.end() ; ++it) + { + it->pLight->render(); + } + +} +//-------------------------------------------------------------------------------- + + +Vector3 Scene::getCenter(){ + Vector3 center; + if(mAllEntities.size() ==1) + { + center.x = 0.; + center.y = 0.; + center.z = 0.; + } + else + { + center = (mEntities[0].pEntity)->getCenter(); + } + return center; +} + +void Scene::rotateObjet(float dx, float dy, std::vector camParam){ + if(mAllEntities.size() !=3) + { + (mEntities[0].pEntity)->Rotation(dx,dy,camParam); + } +} + +Entity* Scene::getEntity(){ + +return mEntities[0].pEntity; +} + +void Scene::afficheInfo(int split) +{ + for(EntityList::iterator it=mEntities.begin() ; it!=mEntities.end() ; ++it) + { + it->pEntity->afficheInfo(split); + } +} + +void Scene::fDensity(int coverage, Density *pDensity) +{ + for(EntityList::iterator it=mEntities.begin() ; it!=mEntities.end() ; ++it) + { + it->pEntity->fDensity(coverage,pDensity); + } +} + +bool Scene::isTextureEnable(){ + return textureEnable; +} + +void Scene::setTextureEnable(bool b){ + textureEnable = b; +} + +bool Scene::isEmpty(){ + if(mEntities.size()==0) return true; + else return false; +} diff --git a/src/Scene.h b/src/Scene.h new file mode 100644 index 0000000..d6cbfc8 --- /dev/null +++ b/src/Scene.h @@ -0,0 +1,145 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Scene_h_ +#define _Scene_h_ + +#include +#include + +#include "Entity.h" +#include "Light.h" +#include "Density.h" + +#include "Color.h" + +class ShadowMap; + +/** Classe permettant de gerer une scene complete. +*/ + +/** + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Scene +{ +public: + Scene(); + virtual ~Scene(); + + /** Ajoute un objet dans la scene + @param pObj pointeur sur l'objet a ajouter. + @param castShadow indique si l'objet genere des ombres projetees ou non. + */ + void add(Entity* pObj, bool castShadow = true); + void remove(bool delMesh = true); + + /** Ajoute une source lumineuse dans la scene + @param pObj pointeur sur la lumiere a ajouter. + @param castShadow indique si la lumiere projete des ombress ou non. + */ + void add(Light* pLight, bool castShadow = false); + + Entity* getByName(const QString& name); + + template T* getByName(const QString& name) + { + EntityMap::const_iterator entity_iter = mAllEntities.find(name); + if(entity_iter!=mAllEntities.end()) + { + return dynamic_cast(entity_iter->second); + } + + return 0; + } + + void setAmbient(const Color& c); + const Color& getAmbient(void) const; + + /** Trace la scene. + */ + virtual void render(void); + + bool isShadowEnabled(void) const; + void setShadowEnabled(bool on); + + Vector3 getCenter(void); + void rotateObjet(float dx, float dy, std::vector camParam); + void afficheInfo(int split); + void fDensity(int coverage, Density *pDensity); + Entity* getEntity(); + /** + @name isTextureEnable + @brief pour voir si l'objet peut etre textute ou non ou s'il y a un objet dans la scene + */ + bool isTextureEnable(); + /** + @name setTextureEnable + @brief pour authoriser ou non le placage de texture sur l'objet de la scene + */ + void setTextureEnable(bool b); + + bool isEmpty(); +protected: + + typedef std::map EntityMap; + + struct EntityElement + { + EntityElement(Entity* e, bool c) + : pEntity(e), castShadow(c) + {} + Entity* pEntity; + bool castShadow; + }; + typedef std::vector EntityList; + + struct LightElement + { + LightElement(Light* e, bool c) + : pLight(e), castShadow(c) + {} + Light* pLight; + bool castShadow; + }; + typedef std::vector LightList; + + // liste les objets + EntityList mEntities; + + // liste des sources lumineuses + LightList mLights; + + EntityMap mAllEntities; + + Color mAmbient; + + ShadowMap* mShadowMap; + bool mShadowEnabled; + +protected: + + //-------------------------------------------------------------------------------- + // fonctions utiles pour les differents mode de rendu + void activateLights(void); + void releaseLights(void); + void renderObjects(bool activateMaterial = true); + void renderOccluders(bool activateMaterial = false); + //-------------------------------------------------------------------------------- + + /** + texture applicable ou pas + */ + bool textureEnable; + +}; + +#endif diff --git a/src/ShadowMap.cpp b/src/ShadowMap.cpp new file mode 100644 index 0000000..bf2c345 --- /dev/null +++ b/src/ShadowMap.cpp @@ -0,0 +1,178 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +//#include "OpenGL.h" + +#include + +#define INT32 _INT32 +#include "OffScreenRendering.h" +#undef INT32 + +#include "ShadowMap.h" +#include "Light.h" + + +/*******************************************************************/ +/* Début code à faire/completer par l'étudiant */ +/* shadow map */ +/*******************************************************************/ + +Matrix4 ShadowMap::scaleBiasMatrix( + 0.5, 0, 0, 0.5, + 0, 0.5, 0, 0.5, + 0, 0, 0.5, 0.5, + 0, 0, 0, 1.0 +); + +float ShadowMap::configEpsilon = 4.; + +ShadowMap::ShadowMap(int width, int height, int stage) + : mpLight(0) +{ + mTextureUnit = GL_TEXTURE0 + stage; + mPBuffer = new OffScreenRendering(width,height,true); + + // à faire : créer la texture de profondeur. + glGenTextures(1, &mTexId); + glBindTexture(GL_TEXTURE_2D, mTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, Color::WHITE); + glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT24_ARB,width,height,0, GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,0); GL_TEST_ERR; +} + +ShadowMap::~ShadowMap() +{ + // à faire : détruire la texture OpenGL. + glDeleteTextures(1, &mTexId); + delete mPBuffer; +} + +void ShadowMap::setLight(Light* pLight) +{ + if(pLight->getType()==Light::LT_SPOT) + { + mpLight = pLight; + } +} + +void ShadowMap::beginUpdate(void) +{ + // à faire : activer le PBuffer + // à faire : positionner la caméra OpenGL au niveau du spot + // à faire : décalage des polygones + + if(!mpLight) + { + std::cerr << "No valid light was setted\n"; + exit(1); + } + + mPBuffer->begin(); + glEnable(GL_DEPTH_TEST); + glClear(GL_DEPTH_BUFFER_BIT); + + Matrix4 lightview, lightproj; + + // render the scene from light source + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluPerspective( mpLight->getAperture()*2., 1.0, 3., 10e6); + glGetFloatv(GL_PROJECTION_MATRIX, (lightproj[0])); + lightproj = lightproj.transpose(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + // Vector3 camPos = mpLight->getPosition(); + // Vector3 lightDir = mpLight->getDirection(); + // Vector3 camTarget = camPos + lightDir; + // Vector3 camUp = lightDir.perpendicular(); + //gluLookAt(camPos.x, camPos.y, camPos.z, camTarget.x, camTarget.y, camTarget.z, camUp.x, camUp.y, camUp.z); + glGetFloatv(GL_MODELVIEW_MATRIX, (lightview[0])); + lightview = lightview.transpose(); + + mSceneToLightMatrix = scaleBiasMatrix * lightproj * lightview; + + glPolygonOffset(configEpsilon, 1.1f); + glEnable(GL_POLYGON_OFFSET_FILL); +} + +void ShadowMap::endUpdate(void) +{ + // à faire : restaurer les états OpenGL + // à faire : copier le depth buffer dans la texture de profondeur + // à faire : désactiver le PBuffer + + glDisable(GL_POLYGON_OFFSET_FILL); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glBindTexture(GL_TEXTURE_2D,mTexId); + mPBuffer->copyToTexture(&mTexId); + + mPBuffer->end(); +} + +void ShadowMap::activate(void) +{ + // à faire : activer la matrice de passage de la scène à la shadow map via la génération automatique des coordonnées de texture ou la matrice de transformation des coordonnées de texture + + // à faire : activer la texture de profondeur + + glActiveTexture(mTextureUnit); + glBindTexture(GL_TEXTURE_2D,mTexId); + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_S, GL_EYE_PLANE, mSceneToLightMatrix[0]); + glEnable(GL_TEXTURE_GEN_S); + + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_T, GL_EYE_PLANE, mSceneToLightMatrix[1]); + glEnable(GL_TEXTURE_GEN_T); + + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_R, GL_EYE_PLANE, mSceneToLightMatrix[2]); + glEnable(GL_TEXTURE_GEN_R); + + glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_Q, GL_EYE_PLANE, mSceneToLightMatrix[3]); + glEnable(GL_TEXTURE_GEN_Q); + + glEnable(GL_TEXTURE_2D); + + glActiveTexture(GL_TEXTURE0); +} + + +void ShadowMap::release(void) +{ + // à faire : restaurer les états OpenGL + + glActiveTexture(mTextureUnit); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_Q); + glActiveTexture(GL_TEXTURE0); +} + +/*******************************************************************/ +/* Fin code à faire/completer par l'étudiant */ +/* shadow map */ +/*******************************************************************/ + diff --git a/src/ShadowMap.h b/src/ShadowMap.h new file mode 100644 index 0000000..1a442a3 --- /dev/null +++ b/src/ShadowMap.h @@ -0,0 +1,104 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _ShadowMap_h_ +#define _ShadowMap_h_ + +class OffScreenRendering; +class Light; +class Entity; + + +#include +#include "OpenGL.h" +#include "Matrix4.h" + + +/** Classe permetant de gérer une shadow map. + - Une seule instance d'une ShadowMap est généralement suffisante, même pour gérer plusieurs sources lumineuses. + - Son utilisation doit être très simple : + - Pour la mise à jour : + \code + setLight(light); + beginUpdate(); + // tracer les occluders + endUpdate(); + \endcode + - Au moment du rendu de la scène : + \code + activate(); + // tracer les objets de la scène + release(); + \endcode + +\note classe à completer entièrement par l'étudiant +*/ +class ShadowMap +{ +public: + + /** Constructeur. + \param width largeur de la texture de profondeur. + \param height hauteur de la texture de profondeur. + \param stage numéro de l'unité de texture à utiliser. + */ + ShadowMap(int width=1024, int height=1024, int stage=3); + + ~ShadowMap(); + + /** Définie la source lumineuse à utiliser (doit être de type "spot") + */ + void setLight(Light* pLight); + + /** Méthode à appeler pour mettre à jour la shadow map. + */ + void beginUpdate(void); + + /** Méthode à appeler à la fin de la mise à jour. + */ + void endUpdate(void); + + /** Active les état OpenGL permettant le rendu avec la shadow map. + */ + void activate(void); + + /** Désactive les état OpenGL. + */ + void release(void); + +public: + + /** Epsilon pour le décalage des polygones + */ + static float configEpsilon; + +protected: + + /** Contexte de rendu hors écran. + */ + OffScreenRendering *mPBuffer; + + /** Source lumineuse courante. + */ + Light* mpLight; + + static Matrix4 scaleBiasMatrix; + + /** Unité de texture à utiliser. + */ + GLenum mTextureUnit; + + /** Numéro OpenGL de la texture. + */ + GLuint mTexId; + + /** Matrice de passage de l'espace scene à l'espace de la shadow map. + */ + Matrix4 mSceneToLightMatrix; +}; + +#endif diff --git a/src/TextureLayer.cpp b/src/TextureLayer.cpp new file mode 100644 index 0000000..9b7b1aa --- /dev/null +++ b/src/TextureLayer.cpp @@ -0,0 +1,129 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "TextureLayer.h" +//#include +#include +#include + +/*******************************************************************/ +/* Début code à  faire/completer par l'étudiant */ +/* Texture */ +/*******************************************************************/ +TextureLayer::TextureLayer(const QString& fileName, const QString& semantic) + : mSemantic(semantic), mBlendMode(GL_MODULATE), mWrapMode(GL_REPEAT) +{ + QImage img = QImage(fileName).rgbSwapped(); // swapRGB : pour être conforme avec OpenGL + + if(!img.isNull()) + { + img = img.mirrored(); // pour être conforme avec OpenGL + GLenum fmt = GL_RGB; + + switch(img.depth()) + { + case 8: + fmt = GL_LUMINANCE; + break; + case 16: + fmt = GL_LUMINANCE_ALPHA; + break; + case 24: + fmt = GL_RGB; + break; + case 32: + fmt = GL_RGBA; + break; + default: + std::cerr << "Error in TextureLayer, bpp = " << img.depth() << " !" << std::endl; + exit(1); + } + + + glGenTextures(1, &mTexId); GL_TEST_ERR + + glBindTexture(GL_TEXTURE_2D, mTexId); + + gluBuild2DMipmaps(GL_TEXTURE_2D, fmt, img.width(), img.height(), fmt, GL_UNSIGNED_BYTE, img.bits()); GL_TEST_ERR; + + glBindTexture(GL_TEXTURE_2D,0); + + mFilteringModes[1] = GL_LINEAR; + mFilteringModes[0] = GL_LINEAR_MIPMAP_LINEAR; + } + else if (fileName.contains(".tga", Qt::CaseInsensitive)) + { + tga=new TgaLoader(fileName); + glGenTextures(1, &mTexId); + glBindTexture(GL_TEXTURE_2D, mTexId); + gluBuild2DMipmaps ( GL_TEXTURE_2D, tga->getInternalFormat(), + tga->getWidth(), tga->getHeight(), + tga->getFormat(), GL_UNSIGNED_BYTE, tga->getTexels()); + glBindTexture(GL_TEXTURE_2D,0); + + mFilteringModes[1] = GL_LINEAR; + mFilteringModes[0] = GL_LINEAR_MIPMAP_LINEAR; + } + else + std::cerr<<"Invalid format image"< +#include "OpenGL.h" +#include + +#include "Vector3.h" +#include "Transform.h" + +#include "TgaLoader.h" +class TextureLayer +{ +public: + + /** Constructeur d'une texture + \param fileName nom du fichier contenant l'image + \param semantic sémantique de la texture (DiffuseMap, AlphaMap, EnvironementMap, ...) + \note à  faire par l'étudiant + */ + TextureLayer(const QString& fileName, const QString& semantic = "DiffuseMap"); + + /** retourne la sémentique de la texture + */ + const QString& getSemantic(void) const; + + /** Active les états OpenGL de la texture. + \note à  faire par l'étudiant + */ + void activate(void); + + /** Désactive les états OpenGL de la texture. + \note à  faire par l'étudiant + */ + void release(void); + + /** Spécifie le mode de filtrage pour la réduction et l'agrandissement (GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR, ...). + */ + void setFilteringMode(GLenum minMode, GLenum magMode); + + /** Spécifie le mode de mélange entre la texture et la couleur du fragment (GL_MODULATE, GL_REPLACE, GL_ADD, ...) + */ + void setBlendMode(GLenum mode); + + /** Spécifie le mode de répétition de la texture (GL_REPEAT ou GL_CLAMP). + */ + void setWrapMode(GLenum mode); + + /** Spécifie les transformations des coordonnées de textures. + */ + void setTransform(const Transform& t); + const Transform& getTransform(void); + +protected: + + QString mSemantic; + + GLenum mBlendMode; + GLenum mWrapMode; + GLenum mFilteringModes[2]; + + /// numéro OpenGL de la texture. + GLuint mTexId; + + Transform mTransform; + TgaLoader *tga; +}; + +#endif diff --git a/src/TgaLoader.cpp b/src/TgaLoader.cpp new file mode 100644 index 0000000..ecc497a --- /dev/null +++ b/src/TgaLoader.cpp @@ -0,0 +1,548 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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 "TgaLoader.h" +#include +#include + +TgaLoader::TgaLoader(const QString& fileName) +{ + FILE *fp; + colormap=NULL; + + fp = fopen (fileName.toAscii(), "rb"); + if (!fp) + { + std::cerr<<"error: couldn't open "<> 3)); + fread (colormap, sizeof (GLubyte), header.cm_length + * (header.cm_size >> 3), fp); + } + + /* memory allocation */ + texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) *texinfo->width * texinfo->height * texinfo->internalFormat); + if (!texinfo->texels) + { + free (texinfo); + return ; + } + + /* lecture des données pixels de l'image... */ + switch (header.image_type) + { + case 0: + /* no data */ + break; + + case 1: + /* uncompressed 8 bits color index */ + ReadTGA8bits (fp, colormap, texinfo); + break; + + case 2: + /* uncompressed 16-24-32 bits */ + switch (header.pixel_depth) + { + case 16: + ReadTGA16bits (fp, texinfo); + break; + + case 24: + ReadTGA24bits (fp, texinfo); + break; + + case 32: + ReadTGA32bits (fp, texinfo); + break; + } + + break; + + case 3: + /* uncompressed 8 or 16 bits grayscale */ + if (header.pixel_depth == 8) + ReadTGAgray8bits (fp, texinfo); + else /* 16 */ + ReadTGAgray16bits (fp, texinfo); + + break; + + case 9: + /* RLE compressed 8 bits color index */ + ReadTGA8bitsRLE (fp, colormap, texinfo); + break; + + case 10: + /* RLE compressed 16-24-32 bits */ + switch (header.pixel_depth) + { + case 16: + ReadTGA16bitsRLE (fp, texinfo); + break; + + case 24: + ReadTGA24bitsRLE (fp, texinfo); + break; + + case 32: + ReadTGA32bitsRLE (fp, texinfo); + break; + } + + break; + + case 11: + /* RLE compressed 8 or 16 bits grayscale */ + if (header.pixel_depth == 8) + ReadTGAgray8bitsRLE (fp, texinfo); + else /* 16 */ + ReadTGAgray16bitsRLE (fp, texinfo); + + break; + + default: + /* image type is not correct */ + std::cerr<<"error: unknown TGA image typ"<texels); + free (texinfo); + texinfo = NULL; + break; + } + /* désallocations mémoire nécessaires... */ + if (colormap) + free (colormap); + + fclose (fp); +} + + +TgaLoader::~TgaLoader() +{ +} + +void +TgaLoader::GetTextureInfo (tga_header_t *header, gl_texture_t *texinfo) +{ + texinfo->width = header->width; + texinfo->height = header->height; + + switch (header->image_type) + { + case 3: /* grayscale 8 bits */ + case 11: /* grayscale 8 bits (RLE) */ + { + if (header->pixel_depth == 8) + { + texinfo->format = GL_LUMINANCE; + texinfo->internalFormat = 1; + } + else /* 16 bits */ + { + texinfo->format = GL_LUMINANCE_ALPHA; + texinfo->internalFormat = 2; + } + + break; + } + + case 1: /* 8 bits color index */ + case 2: /* BGR 16-24-32 bits */ + case 9: /* 8 bits color index (RLE) */ + case 10: /* BGR 16-24-32 bits (RLE) */ + { + /* 8 bits and 16 bits images will be converted to 24 bits */ + if (header->pixel_depth <= 24) + { + texinfo->format = GL_RGB; + texinfo->internalFormat = 3; + } + else /* 32 bits */ + { + texinfo->format = GL_RGBA; + texinfo->internalFormat = 4; + } + + break; + } + } +} + +void +TgaLoader::ReadTGA24bits (FILE *fp, gl_texture_t *texinfo) +{ + int i; + int taille = texinfo->width * texinfo->height; + for (i = 0; i < taille; ++i) + { + /* read and convert BGR to RGB */ + texinfo->texels[(i * 3) + 2] = (GLubyte)fgetc (fp); + texinfo->texels[(i * 3) + 1] = (GLubyte)fgetc (fp); + texinfo->texels[(i * 3) + 0] = (GLubyte)fgetc (fp); + } +} + +void +TgaLoader::ReadTGA32bits (FILE *fp, gl_texture_t *texinfo) +{ + int i; + int taille = texinfo->width * texinfo->height; + for (i = 0; i < taille; ++i) + { + /* read and convert BGRA to RGBA */ + texinfo->texels[(i * 4) + 2] = (GLubyte)fgetc (fp); + texinfo->texels[(i * 4) + 1] = (GLubyte)fgetc (fp); + texinfo->texels[(i * 4) + 0] = (GLubyte)fgetc (fp); + texinfo->texels[(i * 4) + 3] = (GLubyte)fgetc (fp); + } +} + +void +TgaLoader::ReadTGA16bits (FILE *fp, gl_texture_t *texinfo) +{ + int i; + int taille = texinfo->width * texinfo->height; + unsigned short color; + + for (i = 0; i < taille; ++i) + { + /* read color word */ + color = fgetc (fp) + (fgetc (fp) << 8); + + /* convert BGR to RGB */ + texinfo->texels[(i * 3) + 0] = (GLubyte)(((color & 0x7C00) >> 10) << 3); + texinfo->texels[(i * 3) + 1] = (GLubyte)(((color & 0x03E0) >> 5) << 3); + texinfo->texels[(i * 3) + 2] = (GLubyte)(((color & 0x001F) >> 0) << 3); + } +} + +void +TgaLoader::ReadTGA8bits (FILE *fp, GLubyte *colormap, gl_texture_t *texinfo) +{ + int i; + GLubyte color; + int taille = texinfo->width * texinfo->height; + for (i = 0; i < taille; ++i) + { + /* read index color byte */ + color = (GLubyte)fgetc (fp); + + /* convert to RGB 24 bits */ + texinfo->texels[(i * 3) + 2] = colormap[(color * 3) + 0]; + texinfo->texels[(i * 3) + 1] = colormap[(color * 3) + 1]; + texinfo->texels[(i * 3) + 0] = colormap[(color * 3) + 2]; + } +} + +void +TgaLoader::ReadTGAgray8bits (FILE *fp, gl_texture_t *texinfo) +{ + int i; + int taille = texinfo->width * texinfo->height; + for (i = 0; i < taille; ++i) + { + /* read grayscale color byte */ + texinfo->texels[i] = (GLubyte)fgetc (fp); + } +} + +void +TgaLoader::ReadTGA24bitsRLE (FILE *fp, gl_texture_t *texinfo) +{ + int i, size; + GLubyte rgb[3]; + GLubyte packet_header; + GLubyte *ptr = texinfo->texels; + + while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3) + { + /* read first byte */ + packet_header = (GLubyte)fgetc (fp); + size = 1 + (packet_header & 0x7f); + + if (packet_header & 0x80) + { + /* run-length packet */ + fread (rgb, sizeof (GLubyte), 3, fp); + + for (i = 0; i < size; ++i, ptr += 3) + { + ptr[0] = rgb[2]; + ptr[1] = rgb[1]; + ptr[2] = rgb[0]; + } + } + else + { + /* non run-length packet */ + for (i = 0; i < size; ++i, ptr += 3) + { + ptr[2] = (GLubyte)fgetc (fp); + ptr[1] = (GLubyte)fgetc (fp); + ptr[0] = (GLubyte)fgetc (fp); + } + } + } +} + +void +TgaLoader::ReadTGAgray16bits (FILE *fp, gl_texture_t *texinfo) +{ + int i; + int taille = texinfo->width * texinfo->height; + for (i = 0; i < taille; ++i) + { + /* read grayscale color + alpha channel bytes */ + texinfo->texels[(i * 2) + 0] = (GLubyte)fgetc (fp); + texinfo->texels[(i * 2) + 1] = (GLubyte)fgetc (fp); + } +} + +void +TgaLoader::ReadTGA8bitsRLE (FILE *fp, GLubyte *colormap, gl_texture_t *texinfo) +{ + int i, size; + GLubyte color; + GLubyte packet_header; + GLubyte *ptr = texinfo->texels; + + while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3) + { + /* read first byte */ + packet_header = (GLubyte)fgetc (fp); + size = 1 + (packet_header & 0x7f); + + if (packet_header & 0x80) + { + /* run-length packet */ + color = (GLubyte)fgetc (fp); + + for (i = 0; i < size; ++i, ptr += 3) + { + ptr[0] = colormap[(color * 3) + 2]; + ptr[1] = colormap[(color * 3) + 1]; + ptr[2] = colormap[(color * 3) + 0]; + } + } + else + { + /* non run-length packet */ + for (i = 0; i < size; ++i, ptr += 3) + { + color = (GLubyte)fgetc (fp); + + ptr[0] = colormap[(color * 3) + 2]; + ptr[1] = colormap[(color * 3) + 1]; + ptr[2] = colormap[(color * 3) + 0]; + } + } + } +} + +void +TgaLoader::ReadTGA16bitsRLE (FILE *fp, gl_texture_t *texinfo) +{ + int i, size; + unsigned short color; + GLubyte packet_header; + GLubyte *ptr = texinfo->texels; + + while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3) + { + /* read first byte */ + packet_header = fgetc (fp); + size = 1 + (packet_header & 0x7f); + + if (packet_header & 0x80) + { + /* run-length packet */ + color = fgetc (fp) + (fgetc (fp) << 8); + + for (i = 0; i < size; ++i, ptr += 3) + { + ptr[0] = (GLubyte)(((color & 0x7C00) >> 10) << 3); + ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3); + ptr[2] = (GLubyte)(((color & 0x001F) >> 0) << 3); + } + } + else + { + /* non run-length packet */ + for (i = 0; i < size; ++i, ptr += 3) + { + color = fgetc (fp) + (fgetc (fp) << 8); + + ptr[0] = (GLubyte)(((color & 0x7C00) >> 10) << 3); + ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3); + ptr[2] = (GLubyte)(((color & 0x001F) >> 0) << 3); + } + } + } +} + +void +TgaLoader::ReadTGA32bitsRLE (FILE *fp, gl_texture_t *texinfo) +{ + int i, size; + GLubyte rgba[4]; + GLubyte packet_header; + GLubyte *ptr = texinfo->texels; + + while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 4) + { + /* read first byte */ + packet_header = (GLubyte)fgetc (fp); + size = 1 + (packet_header & 0x7f); + + if (packet_header & 0x80) + { + /* run-length packet */ + fread (rgba, sizeof (GLubyte), 4, fp); + + for (i = 0; i < size; ++i, ptr += 4) + { + ptr[0] = rgba[2]; + ptr[1] = rgba[1]; + ptr[2] = rgba[0]; + ptr[3] = rgba[3]; + } + } + else + { + /* non run-length packet */ + for (i = 0; i < size; ++i, ptr += 4) + { + ptr[2] = (GLubyte)fgetc (fp); + ptr[1] = (GLubyte)fgetc (fp); + ptr[0] = (GLubyte)fgetc (fp); + ptr[3] = (GLubyte)fgetc (fp); + } + } + } +} + + +void +TgaLoader::ReadTGAgray8bitsRLE (FILE *fp, gl_texture_t *texinfo) +{ + int i, size; + GLubyte color; + GLubyte packet_header; + GLubyte *ptr = texinfo->texels; + + while (ptr < texinfo->texels + (texinfo->width * texinfo->height)) + { + /* read first byte */ + packet_header = (GLubyte)fgetc (fp); + size = 1 + (packet_header & 0x7f); + + if (packet_header & 0x80) + { + /* run-length packet */ + color = (GLubyte)fgetc (fp); + + for (i = 0; i < size; ++i, ptr++) + *ptr = color; + } + else + { + /* non run-length packet */ + for (i = 0; i < size; ++i, ptr++) + *ptr = (GLubyte)fgetc (fp); + } + } +} + + +void +TgaLoader::ReadTGAgray16bitsRLE (FILE *fp, gl_texture_t *texinfo) +{ + int i, size; + GLubyte color, alpha; + GLubyte packet_header; + GLubyte *ptr = texinfo->texels; + + while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 2) + { + /* read first byte */ + packet_header = (GLubyte)fgetc (fp); + size = 1 + (packet_header & 0x7f); + + if (packet_header & 0x80) + { + /* run-length packet */ + color = (GLubyte)fgetc (fp); + alpha = (GLubyte)fgetc (fp); + + for (i = 0; i < size; ++i, ptr += 2) + { + ptr[0] = color; + ptr[1] = alpha; + } + } + else + { + /* non run-length packet */ + for (i = 0; i < size; ++i, ptr += 2) + { + ptr[0] = (GLubyte)fgetc (fp); + ptr[1] = (GLubyte)fgetc (fp); + } + } + } +} + +GLuint TgaLoader::getWidth() +{ + return texinfo->width; +} + +GLuint TgaLoader::getHeight() +{ + return texinfo->height; +} + +GLint TgaLoader::getInternalFormat() +{ + return texinfo->internalFormat; +} + +GLenum TgaLoader::getFormat() +{ + return texinfo->format; +} + +GLubyte *TgaLoader::getTexels() +{ + return texinfo->texels; +} diff --git a/src/TgaLoader.h b/src/TgaLoader.h new file mode 100644 index 0000000..d5b1783 --- /dev/null +++ b/src/TgaLoader.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotmail.fr * + * * + * 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 _TgaLoader_h_ +#define _TgaLoader_h_ +#include + +#include +/** + @author GangsTER +*/ +class TgaLoader +{ +public: + TgaLoader(const QString& fileName); + + ~TgaLoader(); + GLuint getWidth(); + GLuint getHeight(); + GLint getInternalFormat(); + GLenum getFormat(); + GLubyte *getTexels(); + +protected: + /* OpenGL texture info */ + typedef struct + { + GLuint width; /* largeur */ + GLuint height; /* hauteur */ + + GLenum format; /* RVB, RVBA, Luminance, Luminance Alpha */ + GLint internalFormat; /* composantes d'un texel */ + + GLubyte *texels; /* données de l'image */ + }gl_texture_t; + + /* tga header */ + #pragma pack(push, 1) + typedef struct + { + GLubyte id_lenght; /* size of image id */ + GLubyte colormap_type; /* 1 is has a colormap */ + GLubyte image_type; /* compression type */ + + short cm_first_entry; /* colormap origin */ + short cm_length; /* colormap length */ + GLubyte cm_size; /* colormap size */ + + short x_origin; /* bottom left x coord origin */ + short y_origin; /* bottom left y coord origin */ + + short width; /* picture width (in pixels) */ + short height; /* picture height (in pixels) */ + + GLubyte pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */ + GLubyte image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */ + }tga_header_t; + #pragma pack(pop) + + void GetTextureInfo (tga_header_t *header, gl_texture_t *texinfo); + void ReadTGA24bits (FILE *fp, gl_texture_t *texinfo); + void ReadTGA32bits (FILE *fp, gl_texture_t *texinfo); + void ReadTGA16bits (FILE *fp, gl_texture_t *texinfo); + void ReadTGA8bits (FILE *fp, GLubyte *colormap, gl_texture_t *texinfo); + void ReadTGAgray8bits (FILE *fp, gl_texture_t *texinfo); + void ReadTGA24bitsRLE (FILE *fp, gl_texture_t *texinfo); + void ReadTGAgray16bits (FILE *fp, gl_texture_t *texinfo); + void ReadTGA8bitsRLE (FILE *fp, GLubyte *colormap, gl_texture_t *texinfo); + void ReadTGA16bitsRLE (FILE *fp, gl_texture_t *texinfo); + void ReadTGA32bitsRLE (FILE *fp, gl_texture_t *texinfo); + void ReadTGAgray8bitsRLE (FILE *fp, gl_texture_t *texinfo); + void ReadTGAgray16bitsRLE (FILE *fp, gl_texture_t *texinfo); + +private: + gl_texture_t *texinfo; + tga_header_t header; + GLubyte *colormap; +}; + +#endif diff --git a/src/Timer.h b/src/Timer.h new file mode 100644 index 0000000..ae990fc --- /dev/null +++ b/src/Timer.h @@ -0,0 +1,64 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Timer_h_ +#define _Timer_h_ + +#include +#include +#include + +class Timer +{ +public: + + typedef double Time; + + Timer() + { + reset(); + } + + ~Timer() + { + } + + inline void start(void) + { + mLast = getTime(); + } + inline void stop(void) + { + mSum += getTime() - mLast; + } + inline void reset(void) + { + mSum = 0.; + } + + inline Time value(void) + { + return mSum; + } + + static Time getTime(void) + { + struct timeval tv; + struct timezone tz; + gettimeofday(&tv, &tz); + return (Time) ((double)tv.tv_sec + 1.e-6 * (double)tv.tv_usec); + } + +protected: + + Time mSum, mLast; + +}; + + +#endif + diff --git a/src/Transform.cpp b/src/Transform.cpp new file mode 100644 index 0000000..a758df2 --- /dev/null +++ b/src/Transform.cpp @@ -0,0 +1,84 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Transform.h" + +Transform::Transform(void) + : mPosition(0., 0. ,0.), mScale(1., 1., 1.) +{ +} + +Transform::Transform(const Matrix4& mat) + : mScale(1., 1., 1.) +{ + mPosition = Vector3(mat[0][3], mat[1][3], mat[2][3]); + Matrix3 rot; + mat.extract3x3Matrix(rot); + mOrientation.FromRotationMatrix(rot); +} + +Transform::Transform(const Transform& t) +{ + mPosition = t.mPosition; + mScale = t.mScale; + mOrientation = t.mOrientation; +} + +const Transform& Transform::operator = (const Transform t) +{ + mPosition = t.mPosition; + mScale = t.mScale; + mOrientation = t.mOrientation; + return *this; +} +void Transform::setIdentity(void) +{ + mPosition = Vector3::ZERO; + mScale = Vector3::UNIT_SCALE; + mOrientation = Quaternion(); +} + +void Transform::setScale(const Vector3& vScale) +{ + mScale = vScale; +} +void Transform::setScale(float sx, float sy, float sz) +{ + mScale = Vector3(sx, sy, sz); +} +void Transform::setScale(float s) +{ + mScale = Vector3(s, s, s); +} +void Transform::setOrientation(const Quaternion& q) +{ + mOrientation = q; +} +void Transform::setOrientation(float angle, float x, float y, float z) +{ + mOrientation.FromAngleAxis(angle, Vector3(x, y, z)); +} +void Transform::setPosition(const Vector3& pos) +{ + mPosition = pos; +} +void Transform::setPosition(float x, float y, float z) +{ + mPosition = Vector3(x, y, z); +} + +void Transform::multCurrentMatrix(void) const +{ + glTranslatef(mPosition.x, mPosition.y, mPosition.z); + float a; + Vector3 axis; + mOrientation.ToAngleAxis(a, axis); + glRotatef(a*180./M_PI, axis.x, axis.y, axis.z); + glScalef(mScale.x, mScale.y, mScale.z); +} + + diff --git a/src/Transform.h b/src/Transform.h new file mode 100644 index 0000000..db33a88 --- /dev/null +++ b/src/Transform.h @@ -0,0 +1,103 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Transform_h_ +#define _Transform_h_ + +#include +#include "Vector3.h" +#include "Quaternion.h" +#include "Matrix3.h" +#include "Matrix4.h" + +class Transform +{ +public: + + Transform(void); + + Transform(const Matrix4& mat); + + Transform(const Transform& t); + + const Transform& operator = (const Transform t); + + void setIdentity(void); + + void setScale(const Vector3& vScale); + void setScale(float sx, float sy, float sz); + void setScale(float s); + inline const Vector3& getScale(void) const + { + return mScale; + } + + void setOrientation(const Quaternion& q); + void setOrientation(float angle, float x, float y, float z); + inline const Quaternion& getOrientation(void) const + { + return mOrientation; + } + + void setPosition(const Vector3& pos); + void setPosition(float x, float y, float z); + inline const Vector3& getPosition(void) const + { + return mPosition; + } + + Matrix4 getMatrix(void) const + { + Matrix4 mat(Matrix4::IDENTITY); + Matrix3 rotMat; + mOrientation.ToRotationMatrix(rotMat); + mat = rotMat; + mat[0][0] *= mScale.x; + mat[0][1] *= mScale.x; + mat[0][2] *= mScale.x; + mat[1][0] *= mScale.y; + mat[1][1] *= mScale.y; + mat[1][2] *= mScale.y; + mat[2][0] *= mScale.z; + mat[2][1] *= mScale.z; + mat[2][2] *= mScale.z; + mat.setTrans(mPosition); + return mat; + } + + Matrix4 getInverseMatrix(void) const + { + Matrix4 mat(Matrix4::IDENTITY); + Matrix3 rotMat; + mOrientation.ToRotationMatrix(rotMat); + mat = rotMat; + mat[0][0] *= mScale.x; + mat[0][1] *= mScale.x; + mat[0][2] *= mScale.x; + mat[1][0] *= mScale.y; + mat[1][1] *= mScale.y; + mat[1][2] *= mScale.y; + mat[2][0] *= mScale.z; + mat[2][1] *= mScale.z; + mat[2][2] *= mScale.z; + mat.setTrans(mPosition); + return mat.inverse(); + } + inline Vector3 toLocalSpace(const Vector3& v) const + { + return getInverseMatrix() * v; + } + + void multCurrentMatrix(void) const; + +protected: + Vector3 mPosition; + Quaternion mOrientation; + Vector3 mScale; +}; + +#endif diff --git a/src/Vector3.cpp b/src/Vector3.cpp new file mode 100644 index 0000000..a868a76 --- /dev/null +++ b/src/Vector3.cpp @@ -0,0 +1,34 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#include "Vector3.h" + +const Vector3 Vector3::ZERO( 0, 0, 0 ); + +const Vector3 Vector3::UNIT_X( 1, 0, 0 ); +const Vector3 Vector3::UNIT_Y( 0, 1, 0 ); +const Vector3 Vector3::UNIT_Z( 0, 0, 1 ); +const Vector3 Vector3::UNIT_SCALE(1, 1, 1); + diff --git a/src/Vector3.h b/src/Vector3.h new file mode 100644 index 0000000..bff6078 --- /dev/null +++ b/src/Vector3.h @@ -0,0 +1,587 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://ogre.sourceforge.net/ + +Copyright © 2000-2002 The OGRE Team +Also see acknowledgements in Readme.html + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +#ifndef __Vector3_H__ +#define __Vector3_H__ + +#include +#include +#include "Quaternion.h" +#include + +/** Standard 3-dimensional vector. + @remarks + A direction in 3D space represented as distances along the 3 + orthoganal axes (x, y, z). Note that positions, directions and + scaling factors can be represented by a vector, depending on how + you interpret the values. +*/ +class Vector3 +{ +public: + float x, y, z; + +public: + inline Vector3() + { + } + + inline Vector3( float fX, float fY, float fZ ) + : x( fX ), y( fY ), z( fZ ) + { + } + + inline Vector3( float afCoordinate[3] ) + : x( afCoordinate[0] ), + y( afCoordinate[1] ), + z( afCoordinate[2] ) + { + } + + inline Vector3( int afCoordinate[3] ) + { + x = (float)afCoordinate[0]; + y = (float)afCoordinate[1]; + z = (float)afCoordinate[2]; + } + + inline Vector3( const float* const r ) + : x( r[0] ), y( r[1] ), z( r[2] ) + { + } + + inline Vector3( const Vector3& rkVector ) + : x( rkVector.x ), y( rkVector.y ), z( rkVector.z ) + { + } + + inline void set(float fX, float fY, float fZ) + { + x = fX; + y = fY; + z = fZ; + } + + inline operator float* () + { + return &x; + } + + inline operator const float* () const + { + return &x; + } + + inline const float* data(void) const + { + return &x; + } + + /** Assigns the value of the other vector. + @param + rkVector The other vector + */ + inline Vector3& operator = ( const Vector3& rkVector ) + { + x = rkVector.x; + y = rkVector.y; + z = rkVector.z; + + return *this; + } + + inline bool operator == ( const Vector3& rkVector ) const + { + return ( x == rkVector.x && y == rkVector.y && z == rkVector.z ); + } + + inline bool operator != ( const Vector3& rkVector ) const + { + return ( x != rkVector.x || y != rkVector.y || z != rkVector.z ); + } + + // arithmetic operations + inline Vector3 operator + ( const Vector3& rkVector ) const + { + Vector3 kSum; + + kSum.x = x + rkVector.x; + kSum.y = y + rkVector.y; + kSum.z = z + rkVector.z; + + return kSum; + } + + inline Vector3 operator - ( const Vector3& rkVector ) const + { + Vector3 kDiff; + + kDiff.x = x - rkVector.x; + kDiff.y = y - rkVector.y; + kDiff.z = z - rkVector.z; + + return kDiff; + } + + inline Vector3 operator * ( float fScalar ) const + { + Vector3 kProd; + + kProd.x = fScalar*x; + kProd.y = fScalar*y; + kProd.z = fScalar*z; + + return kProd; + } + + inline Vector3 operator * ( const Vector3& rhs) const + { + Vector3 kProd; + + kProd.x = rhs.x * x; + kProd.y = rhs.y * y; + kProd.z = rhs.z * z; + + return kProd; + } + + inline Vector3 operator / ( float fScalar ) const + { + assert( fScalar != 0.0 ); + + Vector3 kDiv; + + float fInv = 1.0 / fScalar; + kDiv.x = x * fInv; + kDiv.y = y * fInv; + kDiv.z = z * fInv; + + return kDiv; + } + + inline Vector3 operator - () const + { + Vector3 kNeg; + + kNeg.x = -x; + kNeg.y = -y; + kNeg.z = -z; + + return kNeg; + } + + inline friend Vector3 operator * ( float fScalar, const Vector3& rkVector ) + { + Vector3 kProd; + + kProd.x = fScalar * rkVector.x; + kProd.y = fScalar * rkVector.y; + kProd.z = fScalar * rkVector.z; + + return kProd; + } + + // arithmetic updates + inline Vector3& operator += ( const Vector3& rkVector ) + { + x += rkVector.x; + y += rkVector.y; + z += rkVector.z; + + return *this; + } + + inline Vector3& operator -= ( const Vector3& rkVector ) + { + x -= rkVector.x; + y -= rkVector.y; + z -= rkVector.z; + + return *this; + } + + inline Vector3& operator *= ( float fScalar ) + { + x *= fScalar; + y *= fScalar; + z *= fScalar; + return *this; + } + + inline Vector3& operator /= ( float fScalar ) + { + assert( fScalar != 0.0 ); + + float fInv = 1.0 / fScalar; + + x *= fInv; + y *= fInv; + z *= fInv; + + return *this; + } + + /** Returns the length (magnitude) of the vector. + @warning + This operation requires a square root and is expensive in + terms of CPU operations. If you don't need to know the exact + length (e.g. for just comparing lengths) use squaredLength() + instead. + */ + inline float length () const + { + return sqrt( x * x + y * y + z * z ); + } + + /** Returns the square of the length(magnitude) of the vector. + @remarks + This method is for efficiency - calculating the actual + length of a vector requires a square root, which is expensive + in terms of the operations required. This method returns the + square of the length of the vector, i.e. the same as the + length but before the square root is taken. Use this if you + want to find the longest / shortest vector without incurring + the square root. + */ + inline float squaredLength () const + { + return x * x + y * y + z * z; + } + + /** Calculates the dot (scalar) product of this vector with another. + @remarks + The dot product can be used to calculate the angle between 2 + vectors. If both are unit vectors, the dot product is the + cosine of the angle; otherwise the dot product must be + divided by the product of the lengths of both vectors to get + the cosine of the angle. This result can further be used to + calculate the distance of a point from a plane. + @param + vec Vector with which to calculate the dot product (together + with this one). + @returns + A float representing the dot product value. + */ + inline float dotProduct(const Vector3& vec) const + { + return x * vec.x + y * vec.y + z * vec.z; + } + + /** Normalises the vector. + @remarks + This method normalises the vector such that it's + length / magnitude is 1. The result is called a unit vector. + @note + This function will not crash for zero-sized vectors, but there + will be no changes made to their components. + @returns The previous length of the vector. + */ + inline float normalise() + { + float fLength = sqrt( x * x + y * y + z * z ); + + // Will also work for zero-sized vectors, but will change nothing + if ( fLength > 1e-06 ) + { + float fInvLength = 1.0 / fLength; + x *= fInvLength; + y *= fInvLength; + z *= fInvLength; + } + + return fLength; + } + inline float invsqrt(float & x) + { + float half = 0.5f*x; + int i = *(int*)&x; + i = 0x5f3759df - (i >> 1); + x = *(float*)i; // *(float*)&i -> changement pour éviter des warnings + x = x*(1.5f - half*x*x); + return x; + } + inline void normalisef() + { + float l2 = x*x + y*y + z*z; + float fInvLength = invsqrt(l2); + x *= fInvLength; + y *= fInvLength; + z *= fInvLength; + } + inline void normaliseAndScalef(float s) + { + float l2 = x*x + y*y + z*z; + float scale = invsqrt(l2) * s; + x *= scale; + y *= scale; + z *= scale; + } + /** Calculates the cross-product of 2 vectors, i.e. the vector that + lies perpendicular to them both. + @remarks + The cross-product is normally used to calculate the normal + vector of a plane, by calculating the cross-product of 2 + non-equivalent vectors which lie on the plane (e.g. 2 edges + of a triangle). + @param + vec Vector which, together with this one, will be used to + calculate the cross-product. + @returns + A vector which is the result of the cross-product. This + vector will NOT be normalised, to maximise efficiency + - call Vector3::normalise on the result if you wish this to + be done. As for which side the resultant vector will be on, the + returned vector will be on the side from which the arc from 'this' + to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z) + = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X. + @par + For a clearer explanation, look a the left and the bottom edges + of your monitor's screen. Assume that the first vector is the + left edge and the second vector is the bottom edge, both of + them starting from the lower-left corner of the screen. The + resulting vector is going to be perpendicular to both of them + and will go inside the screen, towards the cathode tube + (assuming you're using a CRT monitor, of course). + */ + inline Vector3 crossProduct( const Vector3& rkVector ) const + { + Vector3 kCross; + + kCross.x = y * rkVector.z - z * rkVector.y; + kCross.y = z * rkVector.x - x * rkVector.z; + kCross.z = x * rkVector.y - y * rkVector.x; + + return kCross; + } + + /** Returns a vector at a point half way between this and the passed + in vector. + */ + inline Vector3 midPoint( const Vector3& vec ) const + { + return Vector3( + ( x + vec.x ) * 0.5, + ( y + vec.y ) * 0.5, + ( z + vec.z ) * 0.5 ); + } + + /** Returns true if the vector's scalar components are all greater + that the ones of the vector it is compared against. + */ + inline bool operator < ( const Vector3& rhs ) const + { + if( x < rhs.x && y < rhs.y && z < rhs.z ) + return true; + return false; + } + + /** Returns true if the vector's scalar components are all smaller + that the ones of the vector it is compared against. + */ + inline bool operator > ( const Vector3& rhs ) const + { + if( x > rhs.x && y > rhs.y && z > rhs.z ) + return true; + return false; + } + + /** Sets this vector's components to the minimum of its own and the + ones of the passed in vector. + @remarks + 'Minimum' in this case means the combination of the lowest + value of x, y and z from both vectors. Lowest is taken just + numerically, not magnitude, so -1 < 0. + */ + inline void makeFloor( const Vector3& cmp ) + { + if( cmp.x < x ) x = cmp.x; + if( cmp.y < y ) y = cmp.y; + if( cmp.z < z ) z = cmp.z; + } + + /** Sets this vector's components to the maximum of its own and the + ones of the passed in vector. + @remarks + 'Maximum' in this case means the combination of the highest + value of x, y and z from both vectors. Highest is taken just + numerically, not magnitude, so 1 > -3. + */ + inline void makeCeil( const Vector3& cmp ) + { + if( cmp.x > x ) x = cmp.x; + if( cmp.y > y ) y = cmp.y; + if( cmp.z > z ) z = cmp.z; + } + + /** Generates a vector perpendicular to this vector (eg an 'up' vector). + @remarks + This method will return a vector which is perpendicular to this + vector. There are an infinite number of possibilities but this + method will guarantee to generate one of them. If you need more + control you should use the Quaternion class. + */ + inline Vector3 perpendicular(void) const + { + static const float fSquareZero = 1e-06 * 1e-06; + + Vector3 perp = this->crossProduct( Vector3::UNIT_X ); + + // Check length + if( perp.squaredLength() < fSquareZero ) + { + /* This vector is the Y axis multiplied by a scalar, so we have + to use another axis. + */ + perp = this->crossProduct( Vector3::UNIT_Y ); + } + + return perp; + } + /** Generates a new random vector which deviates from this vector by a + given angle in a random direction. + @remarks + This method assumes that the random number generator has already + been seeded appropriately. + @param + angle The angle at which to deviate in radians + @param + up Any vector perpendicular to this one (which could generated + by cross-product of this vector and any other non-colinear + vector). If you choose not to provide this the function will + derive one on it's own, however if you provide one yourself the + function will be faster (this allows you to reuse up vectors if + you call this method more than once) + @returns + A random vector which deviates from this vector by angle. This + vector will not be normalised, normalise it if you wish + afterwards. + */ + /* + inline Vector3 randomDeviant( + float angle, + const Vector3& up = Vector3::ZERO ) const + { + Vector3 newUp; + + if (up == Vector3::ZERO) + { + // Generate an up vector + newUp = this->perpendicular(); + } + else + { + newUp = up; + } + + // Rotate up vector by random amount around this + Quaternion q; + q.FromAngleAxis( random() * 2.*M_PI, *this ); + newUp = q * newUp; + + // Finally rotate this by given angle around randomised up + q.FromAngleAxis( angle, newUp ); + return q * (*this); + } + */ + + /** Gets the shortest arc quaternion to rotate this vector to the destination + vector. + @remarks + Don't call this if you think the dest vector can be close to the inverse + of this vector, since then ANY axis of rotation is ok. + */ + Quaternion getRotationTo(const Vector3& dest) const + { + // Based on Stan Melax's article in Game Programming Gems + Quaternion q; + // Copy, since cannot modify local + Vector3 v0 = *this; + Vector3 v1 = dest; + v0.normalise(); + v1.normalise(); + + Vector3 c = v0.crossProduct(v1); + + // NB if the crossProduct approaches zero, we get unstable because ANY axis will do + // when v0 == -v1 + float d = v0.dotProduct(v1); + // If dot == 1, vectors are the same + if (d >= 1.0f) + { + return Quaternion::IDENTITY; + } + float s = sqrt( (1+d)*2 ); + float invs = 1 / s; + + + q.x = c.x * invs; + q.y = c.y * invs; + q.z = c.z * invs; + q.w = s * 0.5; + return q; + } + + /** Returns true if this vector is zero length. */ + inline bool isZeroLength(void) const + { + float sqlen = (x * x) + (y * y) + (z * z); + return (sqlen < (1e-06 * 1e-06)); + + } + + /** As normalise, except that this vector is unaffected and the + normalised vector is returned as a copy. */ + inline Vector3 normalisedCopy(void) const + { + Vector3 ret = *this; + ret.normalise(); + return ret; + } + + /** Calculates a reflection vector to the plane with the given normal . + @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not. + */ + inline Vector3 reflect(const Vector3& normal) + { + return Vector3( ( 2 * this->dotProduct(normal) * normal ) - *this ); + } + + // special points + static const Vector3 ZERO; + static const Vector3 UNIT_X; + static const Vector3 UNIT_Y; + static const Vector3 UNIT_Z; + static const Vector3 UNIT_SCALE; + + /** Function for writing to a stream. + */ + inline friend std::ostream& operator << + ( std::ostream& o, const Vector3& v ) + { + o << "[" << v.x << ", " << v.y << ", " << v.z << "]"; + return o; + } +}; + +#endif diff --git a/src/Viewer.cpp b/src/Viewer.cpp new file mode 100644 index 0000000..2c5200d --- /dev/null +++ b/src/Viewer.cpp @@ -0,0 +1,382 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#include "Viewer.h" +//#include "Density.h" +#include "OpenGL.h" +#include "Color.h" +#include "Scene.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +Viewer::Viewer(QWidget *parent) + : QGLWidget(parent,0,0), mTrackMode(TM_NO_TRACK), mWireFrame(false), mpScene(0), pDensity(NULL), DW_AXES(false), modeSplit(false), fondBlanc(false), modeFusion(false), numViewPort(1), border(true),isRotatePossible(true) +{ + mCamera = new Camera(); +} + +Viewer::~Viewer() +{ +} + +void Viewer::attachScene(Scene* pScene, Scene* pScene2) +{ + mpScene = pScene; + mpScene2 = pScene2; +} + +void Viewer::attachDensity(Density * _pDensity) +{ + pDensity = _pDensity ; +} + +void Viewer::freeDensity() +{ + if (pDensity!=NULL) + { + delete pDensity; + } + pDensity=NULL; +} + +void Viewer::initializeGL() +{ + // set defaults parameters + //met le fond en noir transparent + glClearColor(0., 0., 0., 0.0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + glDisable(GL_COLOR_MATERIAL); + glEnable(GL_NORMALIZE); + glDisable(GL_BLEND); + //activation et test de transparence + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.0f); + glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_3D); + emit glInitialized(); +} + + +void Viewer::setWireframeEnabled(bool on) +{ + mWireFrame = on; + updateGL(); +} +bool Viewer::isWireframeEnabled(void) const +{ + return mWireFrame; +} + +void Viewer::resizeGL(int width, int height) +{ + mWidth = width; + mHeight = height; +} + +void Viewer::paintGL() +{ + int vp1X, vp1Y, vp1W, vp1H, + vp2X, vp2Y, vp2W, vp2H; +// Choix du mode Split Screen + if (modeSplit) + { + vp1X=0; vp1Y=0; + vp1W=mWidth/2; vp1H=mHeight; + + vp2X=mWidth/2; vp2Y=0; + vp2W=mWidth/2; vp2H=mHeight; + } +// Choix du mode Fusion + else if (modeFusion) + { + vp1X=0; vp1Y=0; + vp1W=mWidth; vp1H=mHeight; + + vp2X=0; vp2Y=0; + vp2W=mWidth; vp2H=mHeight; + } +// Choix du mode Normal + else + { + vp1X=0; vp1Y=0; + vp1W=mWidth; vp1H=mHeight; + + vp2X=0; vp2Y=0; + vp2W=mWidth; vp2H=mHeight; + } + mCamera->setViewportSize(vp1X,vp1Y,vp1W, vp1H); + + // Clear buffers + glDisable(GL_COLOR_MATERIAL); + glClearStencil(0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + if (modeFusion) glEnable (GL_SCISSOR_TEST); + + if(mWireFrame) + { + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + glDisable(GL_LIGHTING); + } + else + { + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glEnable(GL_LIGHTING); + } + + Timer t; + t.start(); + + mCamera->renderGLStates(); + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); + glColor4f(1., 1., 1. ,1.); + + if ((modeSplit| modeFusion) | numViewPort==1) + { + if (glIsEnabled(GL_SCISSOR_TEST)) glScissor (0, 0, mWidth/2, mHeight); + mpScene->render(); + } + + + // Draw world axis + if (DW_AXES) drawAxes(1.0); + + if ((modeSplit| modeFusion) & numViewPort==1) drawSelectionVP(); + + if (pDensity!=NULL) + pDensity->drawDensity(mCamera); + + if ((modeSplit| modeFusion) | numViewPort==2) + { + if (glIsEnabled(GL_SCISSOR_TEST)) glScissor (mWidth/2, 0, mWidth/2, mHeight); + glViewport(vp2X,vp2Y,vp2W, vp2H); + mpScene2->render(); + if (DW_AXES) drawAxes(1.0); + if ((modeSplit| modeFusion) & numViewPort==2) drawSelectionVP(); + } + + glFinish(); + + t.stop(); + float fps=1./t.value(); + QString thetext = QString("FPS : %1").arg(fps); + emit fpsChanged(thetext); + if (modeFusion) glDisable (GL_SCISSOR_TEST); +} + +void Viewer::mousePressEvent ( QMouseEvent * e ) +{ + switch(e->button()) + { + case Qt::LeftButton: + mTrackMode = TM_QUAKE_MOVE_XY;//deplacement vertical/horizontal + break; + case Qt::MidButton: + mTrackMode = TM_QUAKE_WALK;//zoom + break; + case Qt::RightButton: + mTrackMode = TM_QUAKE_ROTATE; + break; + default: + break; + } + mMouseX = e->x(); + mMouseY = e->y(); +} + +void Viewer::mouseReleaseEvent ( QMouseEvent * ) +{ + mTrackMode = TM_NO_TRACK; +} + +void Viewer::mouseMoveEvent ( QMouseEvent * e ) +{ + + if(mTrackMode != TM_NO_TRACK) + { + float dx = (float)(e->x() - mMouseX) / (float)mCamera->getWidth(); + float dy = - ((float)(e->y() - mMouseY) / (float)mCamera->getHeight()); + + switch(mTrackMode) + { + case TM_QUAKE_WALK : + //mCamera->localTranslate(Vector3(0, 0, dy*10)); + mCamera->polarZoom( dy*10); + break; + case TM_QUAKE_MOVE_XY : + //mCamera->localTranslate(Vector3(dx*10, dy*10, 0)); + mCamera->polarRotate(dx*M_PI, dy*M_PI); + break; + case TM_QUAKE_ROTATE : + //mCamera->localRotate(dx*M_PI, dy*M_PI); + if(isRotatePossible){ + mpScene->rotateObjet( dx*M_PI,dy*M_PI,mCamera->getValCam()); + mpScene2->rotateObjet( dx*M_PI,dy*M_PI,mCamera->getValCam()); + } + break; + default: + break; + } + + mMouseX = e->x(); + mMouseY = e->y(); + + } + updateGL(); +} +void Viewer::keyPressEvent ( QKeyEvent * e ) +{ + switch( e->key() ) + { + default:; + } + updateGL(); +} + + + +void Viewer::drawAxes(float length) +{ + static GLUquadricObj *cylindre = gluNewQuadric(); + + glPushAttrib(GL_ALL_ATTRIB_BITS); + + glDisable(GL_LIGHTING); + //glEnable(GL_LIGHTING); + //mpScene->activateLights(); + + glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Color::WHITE); + glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,80.0); + glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + + // X axis + glColor3fv(Color::RED); + glPushMatrix(); + glRotatef(90,0.0,1.0,0.0); + gluCylinder(cylindre, length/50.0, length/50.0, 0.8*length, 10, 10); + glTranslatef(0.0,0.0,0.8*length); + gluCylinder(cylindre, length/30.0, 0.0, 0.2*length, 10, 10); + glPopMatrix(); + + // Y axis + glColor3fv(Color::GREEN); + glPushMatrix(); + glRotatef(-90,1.0,0.0,0.0); + gluCylinder(cylindre, length/50.0, length/50.0, 0.8*length, 10, 10); + glTranslatef(0.0,0.0,0.8*length); + gluCylinder(cylindre, length/30.0, 0.0, 0.2*length, 10, 10); + glPopMatrix(); + + // Z axis + glColor3fv(Color::BLUE); + glPushMatrix(); + gluCylinder(cylindre, length/50.0, length/50.0, 0.8*length, 10, 10); + glTranslatef(0.0,0.0,0.8*length); + gluCylinder(cylindre, length/30.0, 0.0, 0.2*length, 10, 10); + glPopMatrix(); + + glPopAttrib(); +} + +void Viewer::setAxes() +{ + DW_AXES= !DW_AXES ; +} + +Camera *Viewer::getCamera(void) const{ + return mCamera; +} + +void Viewer::setCamera(Camera *camera){ + mCamera=camera; + updateGL(); +} + +void Viewer::maj(){ + mCamera->reinit(mpScene->getCenter()[0],mpScene->getCenter()[1],mpScene->getCenter()[2]); + updateGL(); +} + +void Viewer::changeMode(int mode){ + switch(mode) + { + case 0: + modeSplit=false; + modeFusion=false; + break; + case 1: + modeSplit=true; + modeFusion=false; + break; + case 2: + modeSplit=false; + modeFusion=true; + break; + default:; + } +} + +void Viewer::modifAxes( bool b){ + DW_AXES = b; +} + +void Viewer::selectViewPort(int num){ + numViewPort=num; +} + +void Viewer::drawSelectionVP(){ + if (border) { + float decalage =0.; + if (modeFusion & numViewPort==1) decalage =-0.518; + if (modeFusion & numViewPort==2) decalage =0.515; + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushMatrix(); + glLoadIdentity(); + glDisable(GL_LIGHTING); + glBegin(GL_LINE_LOOP); + glColor3ub(255,0,0); + glVertex3d(-0.515+decalage,-0.69,-1.); + glColor3ub(255,255,0); + glVertex3d(-0.515+decalage,0.69,-1.); + glColor3ub(0,0,255); + glVertex3d(0.515+decalage,0.69,-1.); + glColor3ub(255,255,0); + glVertex3d(0.515+decalage,-0.69,-1.); + glEnd(); + glPopMatrix(); + glPopAttrib(); + } +} + +void Viewer::borderChange() +{ + border=!border; +} + +int Viewer::getViewport() +{ + return numViewPort; +} + +void Viewer::setRotatePossible(bool b){ + isRotatePossible = b; +} + diff --git a/src/Viewer.h b/src/Viewer.h new file mode 100644 index 0000000..2a41b6b --- /dev/null +++ b/src/Viewer.h @@ -0,0 +1,137 @@ + +/*************************************************************************** + * Copyright (C) 2005 by Gael GUENNEBAUD * + * guenneba@irit.fr * + * * + ***************************************************************************/ + +#ifndef _Viewer_h_ +#define _Viewer_h_ + + +#include "OpenGL.h" +#include "Camera.h" +#include "Density.h" +#include "Timer.h" + +#include +#include +#include +#include + +#include + +class Scene; +class Light; +class Entity; + +class QMouseEvent; +class QWheelEvent; +class QKeyEvent; + + +/** Classe principale representant la fenetre OpenGL. C'est ici que l'on doit creer la scene, les objets, les lumieres, la camera ... C'est aussi ici que doivent etre gere les evenements souris et claviers + @version 0.1 + @author Gangster + @date Juin 2007 + \nosubgrouping + */ + +class Viewer : public QGLWidget +{ +Q_OBJECT + +public: + + Viewer(QWidget *parent = 0); + virtual ~Viewer(); + + void setAxes(); + + void attachScene(Scene* pScene, Scene* pScene2); + void attachDensity(Density * _pDensity); + void freeDensity(); + + void setWireframeEnabled(bool on); + bool isWireframeEnabled(void) const; + + Camera *getCamera(void) const; + void setCamera(Camera *camera); + void maj(); + void changeMode(int mode); + void modifAxes(bool b); + void selectViewPort(int num); + void borderChange(void); + int getViewport(); + void setRotatePossible(bool b); +signals: + void glInitialized(void); + void fpsChanged(const QString &); +protected: + + /** Methode appelee automatiquement par QT apres la creation du constext OpenGL. + C'est ici que l'on peut mettre a jour les etats qui ne seront jamais modifies par la suite. + */ + virtual void initializeGL (); + + /** Methode appelee automatiquement par QT lorsque le contexte OpenGL change de taille. + Cad, lorsque la fenetre change de taille ! + Cette methode doit entre autre appeler la methode createScene. + */ + virtual void resizeGL ( int width, int height ); + + /** Methode appelee automatiquement par QT lorsque la fenetre OpenGL doit etre redessinee. + Pour forcer l'appel de cette fonction par QT, utilisez la methode (qui est aussi un slot) QGLWidget::updateGL(). + */ + virtual void paintGL (); + + //-------------------------------------------------------------------------------- + // Les methodes suivantes permettent gerer les evenements recus par le widget. + virtual void mousePressEvent ( QMouseEvent * e ); + virtual void mouseReleaseEvent ( QMouseEvent * e ); + virtual void mouseMoveEvent ( QMouseEvent * e ); + //virtual void mouseDoubleClickEvent ( QMouseEvent * e ); + //virtual void wheelEvent ( QWheelEvent * e ); + virtual void keyPressEvent ( QKeyEvent * e ); + //virtual void keyReleaseEvent ( QKeyEvent * e ); + //-------------------------------------------------------------------------------- + + +private: + + /** Methode tracant un repere orthonorme au centre de la scene (en 0,0,0). + @param length longeur des axes + */ + void drawAxes(float length = 1.0); + void drawSelectionVP(); + /** Enum representant le mode de navigation courrant. + */ + enum TrackMode {TM_NO_TRACK=0, TM_POLAR_ROTATE, TM_POLAR_ZOOM, TM_QUAKE_ROTATE, TM_QUAKE_WALK, TM_QUAKE_MOVE_XY}; + + /** Mode de navigation courrant. + */ + TrackMode mTrackMode; + + bool mWireFrame; + + + /** Position precedente de la souris. + */ + int mMouseX, mMouseY; + + Camera *mCamera; + Scene* mpScene; + Scene* mpScene2; + Density * pDensity; + + int mWidth, mHeight; + bool DW_AXES ; + bool modeSplit; + bool fondBlanc; + bool modeFusion; + int numViewPort; + bool border; + bool isRotatePossible; +}; + +#endif diff --git a/src/W_Density.ui b/src/W_Density.ui new file mode 100644 index 0000000..d56d4d1 --- /dev/null +++ b/src/W_Density.ui @@ -0,0 +1,56 @@ + + DensityWindow + + + + 0 + 0 + 495 + 407 + + + + Density Viewer + + + + + + 0 + 0 + 495 + 25 + + + + + + + true + + + true + + + DensiteTex3D + + + + + Afficher la Densité + + + + + Effacer la Densité + + + + + Exit + + + + + + diff --git a/src/W_Main.ui b/src/W_Main.ui new file mode 100644 index 0000000..7fb6208 --- /dev/null +++ b/src/W_Main.ui @@ -0,0 +1,504 @@ + + MyWindow + + + + 0 + 0 + 831 + 639 + + + + Billboard Clouds - For Extreme Model Simplification + + + :/icones/filesystems/exec.png + + + + 48 + 48 + + + + + + + 0 + 0 + 831 + 25 + + + + + Affichage + + + + false + + + Viewport + + + + + + + + + + + + + + + + + + + + + + + + Densité + + + + + + + + Fichier + + + + + + + + + + + false + + + Billboard Cloud + + + + + + + + + + + + + + + Qt::NonModal + + + + 8 + + + + 13 + + + Qt::LeftToRight + + + true + + + Qt::Horizontal + + + + 32 + 32 + + + + Qt::ToolButtonIconOnly + + + 4 + + + + + + + + + + + + + + + + + + + + + + :/icones/filesystems/folder.png + + + Charger un Maillage + + + Ctrl+O + + + + + false + + + :/icones/filesystems/desktop.png + + + Charger une Texture + + + Shift+O + + + + + :/icones/actions/stop.png + + + Quitter + + + Ctrl+Q + + + QAction::QuitRole + + + + + true + + + :/icones/actions/viewmag+.png + + + Afficher/Cacher le Repère + + + Ctrl+R + + + + + :/icones/actions/reload.png + + + Vider la Scène + + + Del + + + + + :/icones/apps/safari1.png + + + Reset Caméra + + + Home + + + + + Crée un Billboard + + + + + Afficher un Billboard + + + Ctrl+B + + + + + test + + + + + true + + + :/icones/apps/xeyes.png + + + Mode Filaire/Plein + + + Ctrl+W + + + + + true + + + :/icones/mimetypes/txt.png + + + Afficher/Cacher les FPS + + + Ctrl+F + + + + + true + + + true + + + Activer/Désactiver VBO + + + Shift+V + + + + + true + + + true + + + Gauche + + + + + true + + + Droite + + + + + true + + + Mode Fusion + + + + + false + + + :/icones/actions/billboard.png + + + Créer un Billboard + + + Shift+B + + + + + false + + + :/icones/actions/bbc.png + + + Créer un Billboard Cloud + + + Ctrl+B + + + + + Charger + + + + + true + + + true + + + :/icones/mimetypes/unknown.png + + + Informations Objet + + + Ctrl+I + + + + + true + + + true + + + :/icones/actions/back.png + + + Gauche + + + Left + + + + + true + + + :/icones/actions/forward.png + + + Droite + + + Right + + + + + true + + + false + + + Mode Fusion + + + 3 + + + + + true + + + true + + + Mode Normal + + + 1 + + + + + :/icones/apps/densite.png + + + Afficher la Densité + + + Ctrl+D + + + + + true + + + false + + + Mode SplitScreen + + + 2 + + + + + true + + + true + + + Densité Texture 3D + + + + + false + + + :/icones/devices/3floppy_unmount.png + + + Sauvegarder + + + Ctrl+S + + + + + true + + + true + + + :/icones/mimetypes/image.png + + + Cadre Fenêtre + + + Space + + + + + true + + + Boite Englobante + + + + + + + + diff --git a/src/application.qrc b/src/application.qrc new file mode 100644 index 0000000..31efdc4 --- /dev/null +++ b/src/application.qrc @@ -0,0 +1,24 @@ + + + icones/actions/back.png + icones/actions/bbc.png + icones/actions/billboard.png + icones/actions/forward.png + icones/actions/reload.png + icones/actions/stop.png + icones/actions/viewmag+.png + icones/apps/densite.png + icones/apps/safari1.png + icones/apps/xeyes.png + icones/devices/3floppy_unmount.png + icones/filesystems/desktop.png + icones/filesystems/exec.png + icones/filesystems/folder.png + icones/filesystems/folder_home.png + icones/mimetypes/image.png + icones/mimetypes/sound.png + icones/mimetypes/txt.png + icones/mimetypes/unknown.png + icones/splashlogo.png + + diff --git a/src/icones/actions/back.png b/src/icones/actions/back.png new file mode 100644 index 0000000..2623a13 Binary files /dev/null and b/src/icones/actions/back.png differ diff --git a/src/icones/actions/bbc.png b/src/icones/actions/bbc.png new file mode 100644 index 0000000..001d174 Binary files /dev/null and b/src/icones/actions/bbc.png differ diff --git a/src/icones/actions/billboard.png b/src/icones/actions/billboard.png new file mode 100644 index 0000000..6860a96 Binary files /dev/null and b/src/icones/actions/billboard.png differ diff --git a/src/icones/actions/editcopy.png b/src/icones/actions/editcopy.png new file mode 100644 index 0000000..001d174 Binary files /dev/null and b/src/icones/actions/editcopy.png differ diff --git a/src/icones/actions/editcut.png b/src/icones/actions/editcut.png new file mode 100644 index 0000000..d5258dd Binary files /dev/null and b/src/icones/actions/editcut.png differ diff --git a/src/icones/actions/editpaste.png b/src/icones/actions/editpaste.png new file mode 100644 index 0000000..18657c2 Binary files /dev/null and b/src/icones/actions/editpaste.png differ diff --git a/src/icones/actions/fileprint.png b/src/icones/actions/fileprint.png new file mode 100644 index 0000000..7b3d96f Binary files /dev/null and b/src/icones/actions/fileprint.png differ diff --git a/src/icones/actions/forward.png b/src/icones/actions/forward.png new file mode 100644 index 0000000..f22b773 Binary files /dev/null and b/src/icones/actions/forward.png differ diff --git a/src/icones/actions/gohome.png b/src/icones/actions/gohome.png new file mode 100644 index 0000000..f6ebfe4 Binary files /dev/null and b/src/icones/actions/gohome.png differ diff --git a/src/icones/actions/openterm.png b/src/icones/actions/openterm.png new file mode 100644 index 0000000..ca3869e Binary files /dev/null and b/src/icones/actions/openterm.png differ diff --git a/src/icones/actions/reload.png b/src/icones/actions/reload.png new file mode 100644 index 0000000..77c4fd5 Binary files /dev/null and b/src/icones/actions/reload.png differ diff --git a/src/icones/actions/stop.png b/src/icones/actions/stop.png new file mode 100644 index 0000000..efcc7fb Binary files /dev/null and b/src/icones/actions/stop.png differ diff --git a/src/icones/actions/up.png b/src/icones/actions/up.png new file mode 100644 index 0000000..42bcc56 Binary files /dev/null and b/src/icones/actions/up.png differ diff --git a/src/icones/actions/viewmag+.png b/src/icones/actions/viewmag+.png new file mode 100644 index 0000000..3282e3d Binary files /dev/null and b/src/icones/actions/viewmag+.png differ diff --git a/src/icones/actions/viewmag-.png b/src/icones/actions/viewmag-.png new file mode 100644 index 0000000..58446bb Binary files /dev/null and b/src/icones/actions/viewmag-.png differ diff --git a/src/icones/apps/clanbomber.png b/src/icones/apps/clanbomber.png new file mode 100644 index 0000000..efcc7fb Binary files /dev/null and b/src/icones/apps/clanbomber.png differ diff --git a/src/icones/apps/densite.png b/src/icones/apps/densite.png new file mode 100644 index 0000000..871af43 Binary files /dev/null and b/src/icones/apps/densite.png differ diff --git a/src/icones/apps/gimp.png b/src/icones/apps/gimp.png new file mode 100644 index 0000000..f466db8 Binary files /dev/null and b/src/icones/apps/gimp.png differ diff --git a/src/icones/apps/go.png b/src/icones/apps/go.png new file mode 100644 index 0000000..49e7d49 Binary files /dev/null and b/src/icones/apps/go.png differ diff --git a/src/icones/apps/k3b.png b/src/icones/apps/k3b.png new file mode 100644 index 0000000..4aaca48 Binary files /dev/null and b/src/icones/apps/k3b.png differ diff --git a/src/icones/apps/kaddressbook.png b/src/icones/apps/kaddressbook.png new file mode 100644 index 0000000..a20b062 Binary files /dev/null and b/src/icones/apps/kaddressbook.png differ diff --git a/src/icones/apps/kate.png b/src/icones/apps/kate.png new file mode 100644 index 0000000..6f41cbe Binary files /dev/null and b/src/icones/apps/kate.png differ diff --git a/src/icones/apps/kcontrol.png b/src/icones/apps/kcontrol.png new file mode 100644 index 0000000..0f7021b Binary files /dev/null and b/src/icones/apps/kcontrol.png differ diff --git a/src/icones/apps/kedit.png b/src/icones/apps/kedit.png new file mode 100644 index 0000000..5dec15c Binary files /dev/null and b/src/icones/apps/kedit.png differ diff --git a/src/icones/apps/kfind.png b/src/icones/apps/kfind.png new file mode 100644 index 0000000..b04710e Binary files /dev/null and b/src/icones/apps/kfind.png differ diff --git a/src/icones/apps/kmail.png b/src/icones/apps/kmail.png new file mode 100644 index 0000000..9d44862 Binary files /dev/null and b/src/icones/apps/kmail.png differ diff --git a/src/icones/apps/konsole.png b/src/icones/apps/konsole.png new file mode 100644 index 0000000..ca3869e Binary files /dev/null and b/src/icones/apps/konsole.png differ diff --git a/src/icones/apps/kopete.png b/src/icones/apps/kopete.png new file mode 100644 index 0000000..2551e8a Binary files /dev/null and b/src/icones/apps/kopete.png differ diff --git a/src/icones/apps/kview.png b/src/icones/apps/kview.png new file mode 100644 index 0000000..46e2356 Binary files /dev/null and b/src/icones/apps/kview.png differ diff --git a/src/icones/apps/kwrite.png b/src/icones/apps/kwrite.png new file mode 100644 index 0000000..0c83664 Binary files /dev/null and b/src/icones/apps/kwrite.png differ diff --git a/src/icones/apps/mac.png b/src/icones/apps/mac.png new file mode 100644 index 0000000..5ddc5f0 Binary files /dev/null and b/src/icones/apps/mac.png differ diff --git a/src/icones/apps/mozilla.png b/src/icones/apps/mozilla.png new file mode 100644 index 0000000..3be22d4 Binary files /dev/null and b/src/icones/apps/mozilla.png differ diff --git a/src/icones/apps/noatun.png b/src/icones/apps/noatun.png new file mode 100644 index 0000000..0057506 Binary files /dev/null and b/src/icones/apps/noatun.png differ diff --git a/src/icones/apps/realplayer.png b/src/icones/apps/realplayer.png new file mode 100644 index 0000000..627531b Binary files /dev/null and b/src/icones/apps/realplayer.png differ diff --git a/src/icones/apps/safari1.png b/src/icones/apps/safari1.png new file mode 100644 index 0000000..fc3a1cb Binary files /dev/null and b/src/icones/apps/safari1.png differ diff --git a/src/icones/apps/safari2.png b/src/icones/apps/safari2.png new file mode 100644 index 0000000..1f2e580 Binary files /dev/null and b/src/icones/apps/safari2.png differ diff --git a/src/icones/apps/safari3.png b/src/icones/apps/safari3.png new file mode 100644 index 0000000..94594a4 Binary files /dev/null and b/src/icones/apps/safari3.png differ diff --git a/src/icones/apps/tux.png b/src/icones/apps/tux.png new file mode 100644 index 0000000..5ef641f Binary files /dev/null and b/src/icones/apps/tux.png differ diff --git a/src/icones/apps/x.png b/src/icones/apps/x.png new file mode 100644 index 0000000..a1232d6 Binary files /dev/null and b/src/icones/apps/x.png differ diff --git a/src/icones/apps/xapp.png b/src/icones/apps/xapp.png new file mode 100644 index 0000000..a1232d6 Binary files /dev/null and b/src/icones/apps/xapp.png differ diff --git a/src/icones/apps/xeyes.png b/src/icones/apps/xeyes.png new file mode 100644 index 0000000..7d26c49 Binary files /dev/null and b/src/icones/apps/xeyes.png differ diff --git a/src/icones/apps/xmms.png b/src/icones/apps/xmms.png new file mode 100644 index 0000000..be07761 Binary files /dev/null and b/src/icones/apps/xmms.png differ diff --git a/src/icones/bbexit.xpm b/src/icones/bbexit.xpm new file mode 100644 index 0000000..49ba611 --- /dev/null +++ b/src/icones/bbexit.xpm @@ -0,0 +1,218 @@ +/* XPM */ +static const char *bbexit[] = { +/* columns rows colors chars-per-pixel */ +"30 30 182 2", +" c black", +". c #010000", +"X c #000100", +"o c #010100", +"O c #010101", +"+ c #030000", +"@ c #020100", +"# c #020001", +"$ c #000002", +"% c #040000", +"& c #060000", +"* c #070000", +"= c #080000", +"- c #090000", +"; c #0A0000", +": c #0B0000", +"> c #0C0000", +", c #0D0000", +"< c #0F0000", +"1 c #150000", +"2 c #160000", +"3 c #160400", +"4 c #180000", +"5 c #190000", +"6 c #1B0000", +"7 c #180300", +"8 c #1C0000", +"9 c #1D0000", +"0 c #160C03", +"q c #160F07", +"w c #1F0900", +"e c #1D0D00", +"r c #101010", +"t c #220000", +"y c #230000", +"u c #270000", +"i c #2D0000", +"p c #2E0000", +"a c #210909", +"s c #320000", +"d c #340000", +"f c #360000", +"g c #300701", +"h c #3B0000", +"j c #310E00", +"k c #2F1700", +"l c #3B1400", +"z c #311F0B", +"x c #2B1D10", +"c c #3F250A", +"v c #392615", +"b c #3B2B2B", +"n c #420000", +"m c #430000", +"M c #440000", +"N c #490000", +"B c #4A0100", +"V c #4C0000", +"C c #4D0000", +"Z c #4D0900", +"A c #530000", +"S c #500700", +"D c #5D0000", +"F c #750000", +"G c #7C0F08", +"H c #462B0E", +"J c #5E2009", +"K c #56381C", +"L c #6A270C", +"P c #69310E", +"I c #5E3F20", +"U c #7A3D20", +"Y c #664524", +"T c #61472C", +"R c #61472E", +"E c #6F4D2A", +"W c #7A472C", +"Q c #6C563E", +"! c #7E5A36", +"~ c #70553A", +"^ c #584E44", +"/ c #605040", +"( c #755C46", +") c #675E55", +"_ c #7E6348", +"` c #7D6C5C", +"' c #7A6C61", +"] c #860000", +"[ c #A00701", +"{ c #B40D07", +"} c #BC1D1A", +"| c #BF1B1C", +" . c #BB1D1C", +".. c #BC1C1C", +"X. c #8D241E", +"o. c #972421", +"O. c #A42723", +"+. c #A02829", +"@. c #B02221", +"#. c #DB0F0E", +"$. c #DF0D0C", +"%. c #D8110E", +"&. c #CE1513", +"*. c #C01A1A", +"=. c #C61819", +"-. c #D11313", +";. c #D31312", +":. c #D41210", +">. c #D51112", +",. c #E90909", +"<. c #E80A09", +"1. c #ED0908", +"2. c #EC0809", +"3. c #F00605", +"4. c #F80302", +"5. c #83592F", +"6. c #84592F", +"7. c #875636", +"8. c #8F5D3C", +"9. c #925C36", +"0. c #85613D", +"q. c #8F683F", +"w. c #966636", +"e. c #976737", +"r. c #986432", +"t. c #996533", +"y. c #9A6533", +"u. c #986633", +"i. c #996535", +"p. c #986635", +"a. c #9A6634", +"s. c #986536", +"d. c #9A6636", +"f. c #93673A", +"g. c #956638", +"h. c #966638", +"j. c #95663A", +"k. c #92653C", +"l. c #91673D", +"z. c #92673C", +"x. c #92673D", +"c. c #90663E", +"v. c #91673F", +"b. c #95653D", +"n. c #99663B", +"m. c #9A623D", +"M. c #98643C", +"N. c #98643D", +"B. c #8E6642", +"V. c #8F6743", +"C. c #8F6744", +"Z. c #8E6841", +"A. c #8F6841", +"S. c #8C6943", +"D. c #8E6843", +"F. c #8A6946", +"G. c #8B6946", +"H. c #8C6844", +"J. c #87694D", +"K. c #846A4F", +"L. c #8A6948", +"P. c #8B6A49", +"I. c #8B6A4B", +"U. c #886B4D", +"Y. c #906844", +"T. c #816B54", +"R. c #867F77", +"E. c #A69F97", +"W. c #C6BFB9", +"Q. c #D3CFCC", +"!. c #E1E0DC", +"~. c #FFF5F6", +"^. c #FFF8F8", +"/. c #FFFEFA", +"(. c #FFFEFB", +"). c #FFFFFB", +"_. c #FFFCFD", +"`. c #FFFFFD", +"'. c #FEFEFE", +"]. c #FFFEFF", +"[. c #FEFFFF", +"{. c gray100", +/* pixels */ +"X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X ", +"X [.[.[.[.[.[.& 0 : & & X X X X X X X X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.& K.Y c 3 : & X X X X X X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: H.j.A.P.R z > : & & X X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.p.w.j.x.q.0.I k > : X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.p.t.t.p.w.x.H.( & X X X [.[.[.[.[.[.[.X ", +"X [.[._.[.[.[.: V.t.t.t.t.p.p.w.x.K.: X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: B.t.t.r.t.p.j.6.l _ & X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.p.p.t.j.V.j 7 T.& X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.t.p.p.N.J f 7 ` & X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.t.p.x.U A X.t ' & X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.t.j.7.M [ } C f p p p p p t b (.[.[.[.X ", +"X [.[.[.[.[.[.: C.p.p.N.B F :.<.#.:.-.-.-.-.-.@.t [.[.[.[.X ", +"X [.[.[.[.[.[.: C.p.w.P h O.$.4.3.2.<.<.<.<.<.*.u [.[.(.[.X ", +"X [.[.[.[.[.[.> V.r.p.9.f G %.1.:.=.| .. . ...+.9 [.[.[.[.X ", +"X [.[.[.[.[.[.> V.p.p.b.W M { &.] A B m m m m s a (.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.t.p.b.L D o.C p 9 2 2 2 ~.^.(.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.p.p.p.m.S Z g > : X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.t.t.p.n.8.u 7 > X X X X [.[.(.[.[.[.[.X ", +"X [.[.[.[.[.[.: V.t.t.t.p.p.x.E 2 / & X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: C.t.t.t.t.p.p.j.5.K.: X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: B.t.t.t.t.r.p.t.w.A.: X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: C.t.r.p.t.t.t.t.t.A.: X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.: P.b.j.p.p.t.t.y.p.A.> X X X [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.(.q v ~ H.x.j.p.t.r.t.A.: X X r [.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.Q.) e w K ! x.x.j.w.A.: [.[.[.[.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.[.(.(.E.^ > z T P.x.F.& [.[.[.[.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.[.[.[.[.[.!.R.x 7 H Q : [.[.[.[.[.[.[.[.[.[.X ", +"X [.[.[.[.[.[.[.[.[.[.[.[.(.(.W.) q X [.[.[.[.[.[.[.[.[.[.X ", +"r X X X X X X X X X X X X X X X X X X X X X X X X X X X X r " +}; diff --git a/src/icones/devices/3floppy_unmount.png b/src/icones/devices/3floppy_unmount.png new file mode 100644 index 0000000..de32b56 Binary files /dev/null and b/src/icones/devices/3floppy_unmount.png differ diff --git a/src/icones/devices/bak/bak2/cdrom_unmount.png b/src/icones/devices/bak/bak2/cdrom_unmount.png new file mode 100644 index 0000000..4aaca48 Binary files /dev/null and b/src/icones/devices/bak/bak2/cdrom_unmount.png differ diff --git a/src/icones/devices/bak/bak2/cdwriter_unmount.png b/src/icones/devices/bak/bak2/cdwriter_unmount.png new file mode 100644 index 0000000..595516a Binary files /dev/null and b/src/icones/devices/bak/bak2/cdwriter_unmount.png differ diff --git a/src/icones/devices/bak/cdwriter_mount.png b/src/icones/devices/bak/cdwriter_mount.png new file mode 100644 index 0000000..ef3eb89 Binary files /dev/null and b/src/icones/devices/bak/cdwriter_mount.png differ diff --git a/src/icones/devices/bak/cdwriter_unmount.png b/src/icones/devices/bak/cdwriter_unmount.png new file mode 100644 index 0000000..6b34c3d Binary files /dev/null and b/src/icones/devices/bak/cdwriter_unmount.png differ diff --git a/src/icones/devices/cdaudio_unmount.png b/src/icones/devices/cdaudio_unmount.png new file mode 100644 index 0000000..9a94168 Binary files /dev/null and b/src/icones/devices/cdaudio_unmount.png differ diff --git a/src/icones/devices/cdrom_unmount.png b/src/icones/devices/cdrom_unmount.png new file mode 100644 index 0000000..3286c5f Binary files /dev/null and b/src/icones/devices/cdrom_unmount.png differ diff --git a/src/icones/devices/hdd_unmount.png b/src/icones/devices/hdd_unmount.png new file mode 100644 index 0000000..cd02984 Binary files /dev/null and b/src/icones/devices/hdd_unmount.png differ diff --git a/src/icones/devices/hdd_unmount_other.png b/src/icones/devices/hdd_unmount_other.png new file mode 100644 index 0000000..9f4ce3d Binary files /dev/null and b/src/icones/devices/hdd_unmount_other.png differ diff --git a/src/icones/devices/nfs_unmount.png b/src/icones/devices/nfs_unmount.png new file mode 100644 index 0000000..8c50c8d Binary files /dev/null and b/src/icones/devices/nfs_unmount.png differ diff --git a/src/icones/devices/print.png b/src/icones/devices/print.png new file mode 100644 index 0000000..7b3d96f Binary files /dev/null and b/src/icones/devices/print.png differ diff --git a/src/icones/fileopen.xpm b/src/icones/fileopen.xpm new file mode 100644 index 0000000..880417e --- /dev/null +++ b/src/icones/fileopen.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *fileopen[] = { +" 16 13 5 1", +". c #040404", +"# c #808304", +"a c None", +"b c #f3f704", +"c c #f3f7f3", +"aaaaaaaaa...aaaa", +"aaaaaaaa.aaa.a.a", +"aaaaaaaaaaaaa..a", +"a...aaaaaaaa...a", +".bcb.......aaaaa", +".cbcbcbcbc.aaaaa", +".bcbcbcbcb.aaaaa", +".cbcb...........", +".bcb.#########.a", +".cb.#########.aa", +".b.#########.aaa", +"..#########.aaaa", +"...........aaaaa" +}; diff --git a/src/icones/fileprint.xpm b/src/icones/fileprint.xpm new file mode 100644 index 0000000..6ada912 --- /dev/null +++ b/src/icones/fileprint.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *fileprint[] = { +" 16 14 6 1", +". c #000000", +"# c #848284", +"a c #c6c3c6", +"b c #ffff00", +"c c #ffffff", +"d c None", +"ddddd.........dd", +"dddd.cccccccc.dd", +"dddd.c.....c.ddd", +"ddd.cccccccc.ddd", +"ddd.c.....c....d", +"dd.cccccccc.a.a.", +"d..........a.a..", +".aaaaaaaaaa.a.a.", +".............aa.", +".aaaaaa###aa.a.d", +".aaaaaabbbaa...d", +".............a.d", +"d.aaaaaaaaa.a.dd", +"dd...........ddd" +}; diff --git a/src/icones/filesave.xpm b/src/icones/filesave.xpm new file mode 100644 index 0000000..bd6870f --- /dev/null +++ b/src/icones/filesave.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *filesave[] = { +" 14 14 4 1", +". c #040404", +"# c #808304", +"a c #bfc2bf", +"b c None", +"..............", +".#.aaaaaaaa.a.", +".#.aaaaaaaa...", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".##........##.", +".############.", +".##.........#.", +".##......aa.#.", +".##......aa.#.", +".##......aa.#.", +"b............." +}; diff --git a/src/icones/filesystems/desktop.png b/src/icones/filesystems/desktop.png new file mode 100644 index 0000000..fc91138 Binary files /dev/null and b/src/icones/filesystems/desktop.png differ diff --git a/src/icones/filesystems/exec.png b/src/icones/filesystems/exec.png new file mode 100644 index 0000000..71389dc Binary files /dev/null and b/src/icones/filesystems/exec.png differ diff --git a/src/icones/filesystems/folder.png b/src/icones/filesystems/folder.png new file mode 100644 index 0000000..3e2a658 Binary files /dev/null and b/src/icones/filesystems/folder.png differ diff --git a/src/icones/filesystems/folder_home.png b/src/icones/filesystems/folder_home.png new file mode 100644 index 0000000..f6ebfe4 Binary files /dev/null and b/src/icones/filesystems/folder_home.png differ diff --git a/src/icones/meshopen.xpm b/src/icones/meshopen.xpm new file mode 100644 index 0000000..526b5a1 --- /dev/null +++ b/src/icones/meshopen.xpm @@ -0,0 +1,96 @@ +/* XPM */ +static const char *meshopen[] = { +"30 30 61 1", +" c black", +". c #010101", +"X c #0B0B0B", +"o c #0C0C0C", +"O c #101010", +"+ c #181818", +"@ c #191919", +"# c gray11", +"$ c gray12", +"% c #202020", +"& c #252525", +"* c gray15", +"= c gray16", +"- c gray19", +"; c #323232", +": c gray20", +"> c #343434", +", c gray21", +"< c #3C3C3C", +"1 c #3E3E3E", +"2 c #3F3F3F", +"3 c gray25", +"4 c #434343", +"5 c #4B4B4B", +"6 c #4C4C4C", +"7 c #505050", +"8 c #585858", +"9 c gray35", +"0 c #5A5A5A", +"q c #606060", +"w c #656565", +"e c gray40", +"r c #676767", +"t c gray44", +"y c #727272", +"u c gray50", +"i c #808080", +"p c gray55", +"a c #8D8D8D", +"s c gray56", +"d c #909090", +"f c #989898", +"g c gray60", +"h c #9A9A9A", +"j c #A0A0A0", +"k c #A5A5A5", +"l c gray65", +"z c gray69", +"x c #B2B2B2", +"c c gray70", +"v c gray", +"b c gray75", +"n c #C0C0C0", +"m c #CBCBCB", +"M c gray80", +"N c #CDCDCD", +"B c #D0D0D0", +"V c gray88", +"C c gray94", +"Z c #FEFEFE", +"A c gray100", +/* pixels */ +" ", +" AAAAAAAnq @ 69 %dCAAAAAAA ", +" AAAAAz%o@osu@MM;32 * zAAAAAA ", +" AAAA7 *yokM*yMMh b6;yo7BAAAA ", +" AAAs 9MXhmm zMMM@hM;ub>@CAAA ", +" AAj6kMu@mhs eyhh*umc*MMs2CAA ", +" AV3MMM@o @@e9>;@ @ eMMiyAA ", +" A3kMu@o6uneeMMMMh;he* 6zM2bA ", +" n9k@@@yMMM9yMMMMzoMMMo; 6k3A ", +" 3eoyM@kMMM;hMMMMM MMM6ez2**n ", +" okMkohhhho9eeeee hhhy>MM6 q ", +" hzu>@;;;; eeeeee ;>* 9hn;% ", +" @@ ;>eMMMM MMMMMM MMMM 9>o* ", +" @unMeeMMmh;MMMMMM>hMMM MMny ", +" hMMMeeMMMh;MMMMMM>hMMM MMMM= ", +" *bMMeeMMMh>MMMMMM;hMMM MMne ", +" X5keeMMMz@MMmMMM;hMMm n6o@ ", +" @s3* @9eee hhhhfho9ee6 o3ue ", +" eMMu*yeee ;;;>;; eeee@MMco; ", +" oemh MMMM;hMMMMM MMMu;Mz= 0 ", +" q6*2zosMMM;hMMMMm MMM6yuoe@V ", +" Voz9 o9MMMeeMMMMh>MMboo@hp0A ", +" AieMz6 *uby9MMMMh;k9XouMb=CA ", +" AA6kMM;*2 o;;;;@ @6 sMM9jAA ", +" AAC>cMhobMz hhhh*iMu2mMyyAAA ", +" AAAB@rM6>MM*hmmz zkXkz;iAAAA ", +" AAAAC2*s6eM96MM66k*s9#jAAAAA ", +" AAAAACy @o*h kk 6 > 7CAAAAAA ", +" AAAAAAAVq ooo %yBAAAAAAAA ", +"O . O" +}; diff --git a/src/icones/meshtexopen.xpm b/src/icones/meshtexopen.xpm new file mode 100644 index 0000000..6dee834 --- /dev/null +++ b/src/icones/meshtexopen.xpm @@ -0,0 +1,292 @@ +/* XPM */ +static const char *meshtexopen[] = { +/* columns rows colors chars-per-pixel */ +"30 30 256 2", +" c #010000", +". c #0C0100", +"X c #1B0100", +"o c #1C0900", +"O c #191400", +"+ c #101010", +"@ c #240000", +"# c #2C0000", +"$ c #2B0C00", +"% c #340000", +"& c #3C0100", +"* c #370A00", +"= c #261100", +"- c #2A1403", +"; c #221C03", +": c #3E1200", +"> c #3E1A00", +", c #2B1B1B", +"< c #26210E", +"1 c #3D2000", +"2 c #383000", +"3 c #262012", +"4 c #333220", +"5 c #440100", +"6 c #4C0100", +"7 c #460F00", +"8 c #4D0E00", +"9 c #540200", +"0 c #5C0200", +"q c #520C02", +"w c #5E0B00", +"e c #5C0909", +"r c #560A0A", +"t c #421400", +"y c #4B1200", +"u c #571600", +"i c #531C02", +"p c #5A1804", +"a c #660000", +"s c #6C0000", +"d c #6C0D00", +"f c #640D07", +"g c #770400", +"h c #7A0000", +"j c #770B00", +"k c #7A0A00", +"l c #7A0D0C", +"z c #6B1101", +"x c #681800", +"c c #751300", +"v c #7D1609", +"b c #4E2700", +"n c #462805", +"m c #5D2302", +"M c #552200", +"N c #4A3A00", +"B c #513700", +"V c #5F3200", +"C c #5C3A00", +"Z c #553C00", +"A c #622E01", +"S c #6D2E00", +"D c #7E2000", +"F c #76240C", +"G c #623300", +"H c #6B3500", +"J c #6F3D0C", +"K c #703000", +"L c #66211C", +"P c #672819", +"I c #75201E", +"U c #79271A", +"Y c #4F3B30", +"T c #6A2E2E", +"R c #623F21", +"E c #623232", +"W c #753130", +"Q c #554A0C", +"! c #6B4300", +"~ c #634800", +"^ c #664600", +"/ c #6A5C00", +"( c #705700", +") c #764E1B", +"_ c #66542E", +"` c #774B26", +"' c #7F7923", +"] c #79773C", +"[ c #6A4544", +"{ c #6B5D54", +"} c #66614E", +"| c #666052", +" . c #7B6D67", +".. c #830500", +"X. c #8F0700", +"o. c #8E0B00", +"O. c #950904", +"+. c #8B1B03", +"@. c #8C140B", +"#. c #9D1400", +"$. c #9E170C", +"%. c #901702", +"&. c #831312", +"*. c #9A1C18", +"=. c #B30C00", +"-. c #A31300", +";. c #B31605", +":. c #B81A0D", +">. c #A91110", +",. c #AA1E16", +"<. c #A81F19", +"1. c #A01D15", +"2. c #BD1E14", +"3. c #B71F1E", +"4. c #BC1C1C", +"5. c #8C210F", +"6. c #81250E", +"7. c #8C300B", +"8. c #872019", +"9. c #812510", +"0. c #992816", +"q. c #BF2100", +"w. c #B7230A", +"e. c #A72819", +"r. c #A82415", +"t. c #B62112", +"y. c #B0221E", +"u. c #972620", +"i. c #982424", +"p. c #AA2424", +"a. c #A32622", +"s. c #B12120", +"d. c #DE0E0E", +"f. c #CB1A03", +"g. c #CD170C", +"h. c #C31808", +"j. c #D51600", +"k. c #DC1201", +"l. c #D3130C", +"z. c #DA110C", +"x. c #C71717", +"c. c #CB1615", +"v. c #C51A14", +"b. c #C21A19", +"n. c #D41211", +"m. c #ED0707", +"M. c #E70B0A", +"N. c #FC0101", +"B. c #C02000", +"V. c #925A0D", +"C. c #885F10", +"Z. c #836500", +"A. c #8C6500", +"S. c #906200", +"D. c #9F6F02", +"F. c #9E6E08", +"G. c #8C7808", +"H. c #8D7801", +"J. c #937502", +"K. c #9D7300", +"L. c #917508", +"P. c #826110", +"I. c #9F6B15", +"U. c #94701A", +"Y. c #A27500", +"T. c #8A7037", +"R. c #825252", +"E. c #9A5E5E", +"W. c #A17946", +"Q. c #975F60", +"!. c #9B7475", +"~. c #A96F6E", +"^. c #9B821B", +"/. c #AA8400", +"(. c #B5910E", +"). c #B19312", +"_. c #B38A3A", +"`. c #ACA53D", +"'. c #BEB43B", +"]. c #C2A01B", +"[. c #D6AD1D", +"{. c #D2B211", +"}. c #D3AD26", +"|. c #D9AA26", +" X c #CCB222", +".X c #CAB228", +"XX c #C3B524", +"oX c #CDAD34", +"OX c #C6B134", +"+X c #D4BF3F", +"@X c #FEFD0D", +"#X c #FCFB1D", +"$X c #FDFC15", +"%X c #CDC437", +"&X c #D7C137", +"*X c #ECD12C", +"=X c #F0CC38", +"-X c #E3D433", +";X c #FFF62C", +":X c #FAFA2B", +">X c #FDF824", +",X c #F7F73E", +" G.S.H C > @ @ : % g 3.b.O.Q.UXUX ", +" UXT &.:.O.9 5 a &.i.z J.fX,X,XpXOX5 I f 9 5 s ;.r.6 DXUX ", +" DXr 7.5 q w k v.n.b.g /.:X#X$X#X*X5 p.c.2.5 A % q T E UX ", +" Y p & ^.FX8 5.g.z.4.a |.2X;X;X;XyX5 p.l.h.q T.kX~ * % SX ", +" . = 8XjXqX# F +.%.v & V.F.D.D.K.I.# U +.+.p B bXjX/ . } ", +" . 9XrX).C > G S S G # d k k k k d # G S m X X A.}.vXN ; ", +" - t & 0 6 J.aX2XiXmX& :.k.k.k.k.B.& mXtXiXmX# d a 6 M . ", +". # l <.s.k K.:X@X>XXX9 k.N.N.N.N.j.9 XX#X#XfX# w.v.,.z X ", +"X I b.z.c...Y.:X@X#XXX9 k.N.N.N.N.k.9 .X#X#XfX% f.M.n.y.% . ", +"@ 6 :.l.v...K.1X#X;XOX9 j.N.N.N.N.j.9 OX;X>XhX% :.z.h...X . ", +". X & w 5.x L.fX Z.Y.D.U.% #.=.=.=.=.#.& C.K.K.( X * ! 5X] ", +" . ' NXsX(.5 c ....j & H H H H H H & d ..k x t sXaXlXO 4 ", +" o H.gX.X& a.c.c.p.0 oXpXiXuXiXbX& p.x.v.c A yX-Xn . | ", +". { t & ^ zX& @.z.M.x.s [.:X#X$X#XtX6 3.M.l.w W._.* i # JX ", +" HX% U w & 5 s v.l.b.k K.X$X>X{.0 s.x.:.5 & 5 F L R.UX ", +" UX!.e 2.;.g 5 9 v 0.z Z.hXpXuXpXOX5 U w 5 9 X.v.r.5 PXUX ", +" UXUXW >.x.s.0 p J % % - Z G H C > @ t ` % O.4.b.h AXUXUX ", +" UXUXLX9 *.b.#.5 vXsX=X% D -.-.+.5 ).bX4X0 t.4.l E.UXUXUX ", +" UXUXUXGX6 ..e.8 Z iXyXm +.g.n.0.% eX+X* F 1.a ~.UXUXUXUX ", +" UXUXUXUXLXE & L t G.mXP.0 g.g.a ) 0Xt m r & CXUXUXUXUXUX ", +" UXUXUXUXUXPX .X @ o 2 7X# $.$.# _ . - @ [ PXUXUXUXUXUXUX ", +" UXUXUXUXUXUXUXJX{ . . o @ @ . 3 .JXUXUXUXUXUXUXUXUX ", +"+ . + " +}; diff --git a/src/icones/mimetypes/image.png b/src/icones/mimetypes/image.png new file mode 100644 index 0000000..d6c4e4f Binary files /dev/null and b/src/icones/mimetypes/image.png differ diff --git a/src/icones/mimetypes/sound.png b/src/icones/mimetypes/sound.png new file mode 100644 index 0000000..1f07e55 Binary files /dev/null and b/src/icones/mimetypes/sound.png differ diff --git a/src/icones/mimetypes/txt.png b/src/icones/mimetypes/txt.png new file mode 100644 index 0000000..51eb800 Binary files /dev/null and b/src/icones/mimetypes/txt.png differ diff --git a/src/icones/mimetypes/unknown.png b/src/icones/mimetypes/unknown.png new file mode 100644 index 0000000..0d0ccc7 Binary files /dev/null and b/src/icones/mimetypes/unknown.png differ diff --git a/src/icones/splashlogo.png b/src/icones/splashlogo.png new file mode 100644 index 0000000..f6403b2 Binary files /dev/null and b/src/icones/splashlogo.png differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..057cd98 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + ***************************************************************************/ + +#include +#include +#include + +#include "BBWindow.h" +#include + +int main( int argc, char ** argv ) { + glutInit(&argc, argv); + Q_INIT_RESOURCE(application); + QApplication app(argc, argv); + + QPixmap pixmap(":/icones/splashlogo.png"); + if(pixmap.isNull()) + { + QMainWindow * mw = new BBWindow(); + QRect r = mw->geometry(); + r.moveCenter(QApplication::desktop()->screenGeometry().center()); + mw->setGeometry(r); + mw->show(); + } + else + { + QSplashScreen splash(pixmap, Qt::WindowStaysOnTopHint); + //Pour la transparence du splash screen + splash.setMask(pixmap.mask()); + splash.show(); + splash.showMessage("Billboard Cloud : v1.0, Equipe GangsTER : 2007"); + app.processEvents(); + QMainWindow * mw = new BBWindow(); + QRect r = mw->geometry(); + r.moveCenter(QApplication::desktop()->screenGeometry().center()); + mw->setGeometry(r); + mw->show(); + sleep(1); + splash.finish(mw); + } + app.connect( &app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()) ); + return app.exec(); +} diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 0000000..a591137 --- /dev/null +++ b/src/src.pro @@ -0,0 +1,89 @@ +# File generated by kdevelop's qmake manager. +# ------------------------------------------- +# Subdir relative project main directory: ./src +# Target is an application: bin/ter + +FORMS += W_Main.ui \ + W_Density.ui +HEADERS += Camera.h \ + Color.h \ + Entity.h \ + Light.h \ + Material.h \ + Matrix3.h \ + Matrix4.h \ + Mesh.h \ + OpenGL.h \ + Plane.h \ + Quaternion.h \ + ShadowMap.h \ + Scene.h \ + TextureLayer.h \ + Timer.h \ + Transform.h \ + Vector3.h \ + Viewer.h \ + Density.h \ + Billboard.h \ + BillboardCloud.h \ + BBWindow.h \ + TgaLoader.h \ + OffScreenRendering.h \ + DensityViewer.h \ + Image.h \ + textfile.h +SOURCES += Camera.cpp \ + Color.cpp \ + Entity.cpp \ + Light.cpp \ + main.cpp \ + Material.cpp \ + Matrix3.cpp \ + Matrix4.cpp \ + Mesh.cpp \ + Plane.cpp \ + Quaternion.cpp \ + ShadowMap.cpp \ + Scene.cpp \ + TextureLayer.cpp \ + Transform.cpp \ + Vector3.cpp \ + Viewer.cpp \ + Density.cpp \ + Billboard.cpp \ + BillboardCloud.cpp \ + BBWindow.cpp \ + TgaLoader.cpp \ + OffScreenRendering.cpp \ + DensityViewer.cpp \ + Image.cpp \ + textfile.cpp +TEMPLATE = app +CONFIG += release \ +warn_on \ +thread \ +qt\ +opengl\ +glew \ +glut +TARGET = bin/ter +CPU = ""$system(uname -m)"" +RESOURCES = application.qrc +MOC_DIR = ../obj/moc +QT += opengl +glut { + unix { + LIBS += -L/usr/X11R6/lib -lglut -lXi -lGLEW -lGL -lX11 -lpng12 + } +} +debug { + DEFINES += DEBUG + OBJECTS_DIR = ../obj/debug +} +release { + OBJECTS_DIR = ../obj/release +} +DESTDIR += ../ \ + .. +PATH += . + diff --git a/src/textfile.cpp b/src/textfile.cpp new file mode 100644 index 0000000..33eea69 --- /dev/null +++ b/src/textfile.cpp @@ -0,0 +1,68 @@ +// textfile.cpp +// +// simple reading and writing for text files +// +// www.lighthouse3d.com +// +// You may use these functions freely. +// they are provided as is, and no warranties, either implicit, +// or explicit are given +////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include + +char *textFileRead(char *fn) { + + FILE *fp; + char *content = NULL; + + int count=0; + + if (fn != NULL) { + fp = fopen(fn,"rt"); + + if (fp != NULL) { + + fseek(fp, 0, SEEK_END); + count = ftell(fp); + rewind(fp); + + if (count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } + } + return content; +} + +int textFileWrite(char *fn, char *s) { + + FILE *fp; + int status = 0; + + if (fn != NULL) { + fp = fopen(fn,"w"); + + if (fp != NULL) { + + if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) + status = 1; + fclose(fp); + } + } + return(status); +} + + + + + + + diff --git a/src/textfile.h b/src/textfile.h new file mode 100644 index 0000000..1c30e53 --- /dev/null +++ b/src/textfile.h @@ -0,0 +1,10 @@ +// textfile.h: interface for reading and writing text files +// www.lighthouse3d.com +// +// You may use these functions freely. +// they are provided as is, and no warranties, either implicit, +// or explicit are given +////////////////////////////////////////////////////////////////////// + +char *textFileRead(char *fn); +int textFileWrite(char *fn, char *s); diff --git a/templates/cpp b/templates/cpp new file mode 100644 index 0000000..0d6377d --- /dev/null +++ b/templates/cpp @@ -0,0 +1,19 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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. * + ***************************************************************************/ diff --git a/templates/h b/templates/h new file mode 100644 index 0000000..0d6377d --- /dev/null +++ b/templates/h @@ -0,0 +1,19 @@ +/*************************************************************************** + * Copyright (C) 2007 by GangsTER * + * coban31@hotamil.fr * + * * + * 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. * + ***************************************************************************/ diff --git a/ter.pro b/ter.pro new file mode 100644 index 0000000..9679d79 --- /dev/null +++ b/ter.pro @@ -0,0 +1,2 @@ +SUBDIRS += src +TEMPLATE = subdirs