Splitting up source files

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
booster
Posts: 15
Joined: Thu Nov 19, 2015 8:53 pm

Splitting up source files

Post by booster »

Hi, its been a very very very long time since I've used C++. I've been attempting to split the program source up into separate files and classes.

I've tried various ways but always end up with seg faults and I'm not sure why or how to seek help for such. Here's one version which attempts to put the gui setup code in its own function (I'd prefer it in a class initialised from within xeng):

main.cpp

Code: Select all

 
/** Example 005 User Interface
*/
#include <irrlicht.h>
#include "driverChoice.h"
 
#include "xeng.h"
 
using namespace irr;
 
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
 
struct SAppContext
{
    IrrlichtDevice *device;
    s32             counter;
    IGUIListBox*    listbox;
};
 
enum{
    GUI_ID_QUIT_BUTTON = 101,
    GUI_ID_NEW_WINDOW_BUTTON,
    GUI_ID_FILE_OPEN_BUTTON,
    GUI_ID_TRANSPARENCY_SCROLL_BAR
};
 
void setSkinTransparency(s32 alpha, irr::gui::IGUISkin * skin)
{
    for (s32 i=0; i<irr::gui::EGDC_COUNT ; ++i)
    {
        video::SColor col = skin->getColor((EGUI_DEFAULT_COLOR)i);
        col.setAlpha(alpha);
        skin->setColor((EGUI_DEFAULT_COLOR)i, col);
    }
}
 
 
class MyEventReceiver : public IEventReceiver
{
public:
    MyEventReceiver(SAppContext & context) : Context(context) { }
 
    virtual bool OnEvent(const SEvent& event)
    {
        if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = Context.device->getGUIEnvironment();
 
            switch(event.GUIEvent.EventType)
            {
            case EGET_SCROLL_BAR_CHANGED:
                if (id == GUI_ID_TRANSPARENCY_SCROLL_BAR)
                {
                    s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                    setSkinTransparency(pos, env->getSkin());
                }
                break;
 
            case EGET_BUTTON_CLICKED:
                switch(id)
                {
                case GUI_ID_QUIT_BUTTON:
                    Context.device->closeDevice();
                    return true;
 
                case GUI_ID_NEW_WINDOW_BUTTON:
                    {
                    Context.listbox->addItem(L"Window created");
                    Context.counter += 30;
                    if (Context.counter > 200)
                        Context.counter = 0;
 
                    IGUIWindow* window = env->addWindow(
                        rect<s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter),
                        false, // modal?
                        L"Test window");
 
                    env->addStaticText(L"Please close me",
                        rect<s32>(35,35,140,50),
                        true, // border?
                        false, // wordwrap?
                        window);
                    }
                    return true;
 
                case GUI_ID_FILE_OPEN_BUTTON:
                    Context.listbox->addItem(L"File open");
                    env->addFileOpenDialog(L"Please choose a file.", true, 0, -1, true);
                    return true;
 
                default:
                    return false;
                }
                break;
 
            case EGET_FILE_SELECTED:
                {
                    // show the model filename, selected in the file dialog
                    IGUIFileOpenDialog* dialog = (IGUIFileOpenDialog*)event.GUIEvent.Caller;
                    Context.listbox->addItem(dialog->getFileName());
                }
                break;
 
            default:
                break;
            }
        }
 
        return false;
    }
 
private:
    SAppContext & Context;
};
 
void app_init_gui(IrrlichtDevice *device, video::IVideoDriver* driver, gui::IGUIEnvironment* env){
    //  We add three buttons. The first one closes the engine. The second
    //  creates a window and the third opens a file open dialog. The third
    //  parameter is the id of the button, with which we can easily identify
    //  the button in the event receiver.
    env->addButton(rect<s32>(10,240,110,240 + 32), 0, GUI_ID_QUIT_BUTTON, L"Quit", L"Exits Program");
    env->addButton(rect<s32>(10,280,110,280 + 32), 0, GUI_ID_NEW_WINDOW_BUTTON, L"New Window", L"Launches a new Window");
    env->addButton(rect<s32>(10,320,110,320 + 32), 0, GUI_ID_FILE_OPEN_BUTTON, L"File Open", L"Opens a file");
    
    //  Now, we add a static text and a scrollbar, which modifies the
    //  transparency of all gui elements. We set the maximum value of
    //  the scrollbar to 255, because that's the maximal value for
    //  a color value.
    //  Then we create an other static text and a list box.
    env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true);
    IGUIScrollBar* scrollbar = env->addScrollBar(true, rect<s32>(150, 45, 350, 60), 0, GUI_ID_TRANSPARENCY_SCROLL_BAR);
    scrollbar->setMax(255);
    scrollbar->setPos(255);
    setSkinTransparency( scrollbar->getPos(), env->getSkin());
 
    // set scrollbar position to alpha value of an arbitrary element
    scrollbar->setPos(env->getSkin()->getColor(EGDC_WINDOW).getAlpha());
 
    env->addStaticText(L"Logging ListBox:", rect<s32>(50,110,250,130), true);
    IGUIListBox * listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
    env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100));
 
    // Store the appropriate data in a context structure.
    SAppContext context;
    context.device = device;
    context.counter = 0;
    context.listbox = listbox;
 
    // Then create the event receiver, giving it that context structure.
    MyEventReceiver receiver(context);
 
    // And tell the device to use our custom event receiver.
    device->setEventReceiver(&receiver);
    
    
    //  And at last, we create a nice Irrlicht Engine logo in the top left corner. 
    env->addImage(driver->getTexture("data/irrlichtlogo2.png"),position2d<int>(10,10));
}
 
int main()
{
    Xeng eng;
    int iret=eng.init();
    
    //  TMP
    IrrlichtDevice* device = eng.device;
    video::IVideoDriver* driver = eng.driver;
    gui::IGUIEnvironment* env = eng.env;
    
    app_init_gui(device,driver,env);
    
    //  That's all, we only have to draw everything.
    eng.loop();
    return 0;
}
 

xeng.h

Code: Select all

 
 
#ifndef ___XAPP
#define ___XAPP
 
#include <irrlicht.h>
#include "driverChoice.h"
 
//#include "xapp.h"
 
using namespace irr;
 
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
 
class Xeng{
    
    public:
        int init();
        int init_driver();
        int init_basics();
        
        int loop();
        
        
        IrrlichtDevice * device;
        video::IVideoDriver* driver;
        gui::IGUIEnvironment* env;
        
        //Xapp* app;
};
 
#endif
 

xeng.cpp

Code: Select all

 
#include "xeng.h"
 
#include <iostream>
using namespace std;
 
int Xeng::loop(){
    while(device->run() && driver){
        if (device->isWindowActive()){
            driver->beginScene(true, true, SColor(0,200,200,200));
            
            env->drawAll();
            
            driver->endScene();
        }
    }
    device->drop();
    return 0;
}
 
 
int Xeng::init()
{
    cout << "Xeng init()" << endl;
    
    int iret=init_driver();
    iret=init_basics();
    
    /*
    //Xapp app;
    app = new Xapp();
    //iret=app->init(device,driver,env);
    app->device=device;
    app->driver=driver;
    app->env=env;
    iret=app->init();
    */
    return 0;
}
 
int Xeng::init_driver(){
    device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640, 480));
    
    //if (device == 0)
    //  return 1; // could not create selected driver.
    return 1;
}
 
int Xeng::init_basics(){
    
    device->setWindowCaption(L"Irrlicht Engine - User Interface Demo");
    device->setResizable(true);
    
    driver = device->getVideoDriver();
    env = device->getGUIEnvironment();
 
    IGUISkin* skin = env->getSkin();
    IGUIFont* font = env->getFont("data/fonthaettenschweiler.bmp");
    if (font)
        skin->setFont(font);
 
    skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);
    
    return 1;
}
 

Many thanks


EDIT: Changed #ifndef in xeng.h
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Splitting up source files

Post by CuteAlien »

You set the event-receiver to the address of a local variable. That object will be destroyed at the end of app_init_gui and next time Irrlicht tries to access the event-receiver it will access invalid memory.

Whenever you pass around references or pointer to local variables you have to be extremely careful that that address will only be used inside that local scope. Otherwise you have to create objects with a longer lifetime. Usually you put them inside other classes which exist longer.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
booster
Posts: 15
Joined: Thu Nov 19, 2015 8:53 pm

Re: Splitting up source files

Post by booster »

Ah, thankyou... Its almost obvious now you say it lol... I did check if it was (directly) called, didn't think about it going out of scope and sent to garbage.


Thankyou again, now back to the drawing board :D
Post Reply