I am posting my version of the code (translated from the Russian version that Digan posted), with some extra comments and some information about how to get the code to compile in Code::Blocks. The information here has been tested with Code::Blocks 10.05, Irrlicht 1.7.2, qt4, and Ubuntu 10.10. I do not know if the steps outlined here can be of any use on any other builds or compilers, but I imagine that the steps will be similar.
1) First thing to do is create a new Qt4 Code::Blocks project. Setup your include directories, and library files so that Code::Blocks can find Irrlicht.
2) Now we need to create a new helper tool which allows Qt to use signals and slots (see here for more information http://doc.qt.nokia.com/latest/moc.html).
2a) Click the "Tools" menu, then select "Configure Tools...".
2b) Enter the following information:
Name: MOC
Executable: /usr/bin/moc
Parameters: ${ACTIVE_EDITOR_FILENAME} -o moc_${ACTIVE_EDITOR_STEM}.cpp
Working directory: ${PROJECT_DIR}
2c) Now click "Ok".
3) Now we need to open up QtCreator and create a new project. Make the window dimensions 800x600 or something similar to that.
3a) Build the QtCreator project to see if the GUI looks right.
3b) We now need to make the .ui file that QtCreator generates into a file that can be read into our program. To do that, open a terminal and enter the following without the quotes "uic filename.ui > ui_filename.h". In my case, I had "uic MainWindow.ui > ui_MainWindow.h".
3c) Include ui_filename.h into your Code::Blocks project.
Here is my ui_MainWindow.h file :
Code: Select all
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created: Wed Aug 24 01:33:57 2011
** by: Qt User Interface Compiler version 4.7.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralWidget;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(800, 600);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 800, 25));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // MAINWINDOW_H
4a) Create two files "QIrrlichtWidget.h" and "QIrrlichtWidget.cpp"
4b) Paste the following codes into the files. I won't explain what is going on because I think everything is fairly well documented.
Code: Select all
// QIrrlichtWidget.h
#ifndef QIRRLICHTWIDGET_H
#define QIRRLICHTWIDGET_H
#include <QWidget>
#include <QResizeEvent>
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
// Our Irrlicht rendering widget
// To have everything compile, we need to run MOC on this file
class QIrrlichtWidget : public QWidget
{
// Macro for the meta-object compiler MOC
Q_OBJECT
public:
explicit QIrrlichtWidget(QWidget *parent = 0);
~QIrrlichtWidget();
// Returns a pointer to the Irrlicht Device
IrrlichtDevice* getIrrlichtDevice();
// Create the Irrlicht device and connect the signals and slots
void init();
signals:
// Signal that its time to update the frame
void updateIrrlichtQuery(IrrlichtDevice* device);
public slots:
// Function called in response to updateIrrlichtQuery. Renders the scene in the widget
void updateIrrlicht(IrrlichtDevice* device);
protected:
virtual void paintEvent(QPaintEvent* event);
virtual void timerEvent(QTimerEvent* event);
virtual void resizeEvent(QResizeEvent* event);
IrrlichtDevice *device;
// We keep the camera inside this widget so we can resize the window dynamically
ICameraSceneNode* camera;
};
#endif // QIRRWIDGET_H
Code: Select all
// QIrrlichtWidget.cpp
#include "QIrrlichtWidget.h"
#include <QtCore/QDebug>
QIrrlichtWidget::QIrrlichtWidget(QWidget *parent) :
QWidget(parent)
{
// Indicates that the widget wants to draw directly onto the screen. (From documentation : http://doc.qt.nokia.com/latest/qt.html)
// Essential to have this or there will be nothing displayed
setAttribute(Qt::WA_PaintOnScreen);
// Indicates that the widget paints all its pixels when it receives a paint event.
// Thus, it is not required for operations like updating, resizing, scrolling and focus changes to erase the widget before generating paint events.
// Not sure this is required for the program to run properly, but it is here just incase.
setAttribute(Qt::WA_OpaquePaintEvent);
// Widget accepts focus by both tabbing and clicking
setFocusPolicy(Qt::StrongFocus);
// Not sure if this is necessary, but it was in the code I am basing this solution off of
setAutoFillBackground(false);
device = 0;
}
QIrrlichtWidget::~QIrrlichtWidget()
{
if(device != 0)
{
device->closeDevice();
device->drop();
}
}
// Create the Irrlicht device and connect the signals and slots
void QIrrlichtWidget::init()
{
// Make sure we can't create the device twice
if(device != 0)
return;
// Set all the device creation parameters
SIrrlichtCreationParameters params;
params.AntiAlias = 0;
params.Bits = 32;
params.DeviceType = EIDT_X11;
params.Doublebuffer = true;
params.DriverType = EDT_OPENGL;
params.EventReceiver = 0;
params.Fullscreen = false;
params.HighPrecisionFPU = false;
params.IgnoreInput = false;
params.LoggingLevel = ELL_INFORMATION;
params.Stencilbuffer = true;
params.Stereobuffer = false;
params.Vsync = false;
// Specify which window/widget to render to
params.WindowId = reinterpret_cast<void*>(winId());
params.WindowSize.Width = width();
params.WindowSize.Height = height();
params.WithAlphaChannel = false;
params.ZBufferBits = 16;
// Create the Irrlicht Device with the previously specified parameters
device = createDeviceEx(params);
if(device)
{
// Create a camera so we can view the scene
camera = device->getSceneManager()->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
}
// Connect the update signal (updateIrrlichtQuery) to the update slot (updateIrrlicht)
connect(this, SIGNAL(updateIrrlichtQuery(IrrlichtDevice*)), this, SLOT(updateIrrlicht(IrrlichtDevice*)));
// Start a timer. A timer with setting 0 will update as often as possible.
startTimer(0);
}
IrrlichtDevice* QIrrlichtWidget::getIrrlichtDevice()
{
return device;
}
void QIrrlichtWidget::paintEvent(QPaintEvent* event)
{
if(device != 0)
{
emit updateIrrlichtQuery(device);
}
}
void QIrrlichtWidget::timerEvent(QTimerEvent* event)
{
// Emit the render signal each time the timer goes off
if (device != 0)
{
emit updateIrrlichtQuery(device);
}
event->accept();
}
void QIrrlichtWidget::resizeEvent(QResizeEvent* event)
{
if(device != 0)
{
dimension2d<u32> widgetSize;
widgetSize.Width = event->size().width();
widgetSize.Height = event->size().height();
device->getVideoDriver()->OnResize(widgetSize);
ICameraSceneNode *cam = device->getSceneManager()->getActiveCamera();
if (cam != 0)
{
cam->setAspectRatio((f32)widgetSize.Height / (f32)widgetSize.Width);
}
}
QWidget::resizeEvent(event);
}
void QIrrlichtWidget::updateIrrlicht( irr::IrrlichtDevice* device )
{
if(device != 0)
{
device->getTimer()->tick();
SColor color (255,100,100,140);
device->getVideoDriver()->beginScene(true, true, color);
device->getSceneManager()->drawAll();
device->getVideoDriver()->endScene();
}
}
// Include the extra Qt file for signals and slots
#include "moc_QIrrlichtWidget.cpp"
If you get an error stating that your structure is incomplete, it is because you are including the moc file at the wrong place. It must go inside the .cpp file, not the .h file.
5) Now we need three more files "MainApplicationWindow.h", "MainApplicationWindow.cpp", "main.cpp". Paste the following codes.
Code: Select all
// MainApplicationWindow.h
// Make sure not to have the same define name as in ui_MainWindow.h
// This gives an incomplete structure error
#ifndef MAINAPPLICATIONWINDOW_H
#define MAINAPPLICATIONWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include "ui_MainWindow.h"
#include "QIrrlichtWidget.h"
// Include the namespace from ui_MainWindow.h
namespace Ui {
class MainWindow;
}
// Class that contains the main window as well as the irrlicht widget
// We use the basic class constructued by QtCreator and modify it
// To have everything compile, we need to run MOC on this file
class MainApplicationWindow : public QMainWindow
{
// Macro for the meta-object compiler MOC
Q_OBJECT
public:
explicit MainApplicationWindow(QWidget *parent = 0);
~MainApplicationWindow();
QIrrlichtWidget* getIrrlichtWidget(){return &irrWidget;}
private:
Ui::MainWindow *ui;
QIrrlichtWidget irrWidget;
};
#endif // MAINAPPLICATIONWINDOW_H
Code: Select all
// MainApplicationWindow.cpp
// Use the file generated by QtCreate and modify it to accomodate the irrlicht widget
#include "MainApplicationWindow.h"
MainApplicationWindow::MainApplicationWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Setup for the Irrlicht Widget
// This is new code that was not in the file generated by QtCreate
irrWidget.setParent(ui->centralWidget);
irrWidget.setGeometry(160, 0, 630, 480);
}
MainApplicationWindow::~MainApplicationWindow()
{
delete ui;
}
// Include the file generated by running MOC on MainApplicationWindow.h
#include "moc_MainApplicationWindow.cpp"
Code: Select all
// main.cpp
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include "MainApplicationWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainApplicationWindow mainWindow;
mainWindow.show();
mainWindow.getIrrlichtWidget()->init();
// Make sure the Irrlicht Device exists before trying to use it
if(mainWindow.getIrrlichtWidget()->getIrrlichtDevice())
{
ISceneManager *smgr = mainWindow.getIrrlichtWidget()->getIrrlichtDevice()->getSceneManager();
IVideoDriver *driver = mainWindow.getIrrlichtWidget()->getIrrlichtDevice()->getVideoDriver();
// Just display a simple mesh
IAnimatedMesh* mesh = smgr->getMesh("sydney.md2");
if (!mesh)
{
mainWindow.getIrrlichtWidget()->getIrrlichtDevice()->drop();
return 1;
}
IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
if (node)
{
node->setMaterialFlag(EMF_LIGHTING, false);
node->setMD2Animation(scene::EMAT_STAND);
node->setMaterialTexture( 0, driver->getTexture("media/sydney.bmp") );
}
}
return app.exec();
}
6a) Select QIrrlichtWidget.h and run the MOC tool on that file. This should generate a file named "moc_QIrrlichtWidget.cpp". If the filename differs, modify the code accordingly, or change the file name.
6b) Select MainApplicationWindow.h and run the MOC tool on that file. Every time that a class contains a Q_OBJECT macro, you must run MOC on it.
6c) Build the project as you would normally, and you're done!
If everything went well, you should be able to see a 800x600 window, with a widget that displays an animated mesh. Adding new controls to this project is now easy. Just go into QtCreator, add the widgets, save the .ui file, run uic on it as stated in part 3, rerun MOC if you change any signals or slots, and you're done!
Wow. Sorry for the super long post. I wanted to make sure this was through enough, because I found that figuring this all out myself was a huge hassle. Hopefully this will help someone along and spare them hours of frustration. I will probably put this up on the Wiki once some people comment and tell me if I've made any big mistakes.
Any questions and comments are welcome, and if you find a bug in my code, or something I missed, please pm me so I can look into it and fix it.