How to access device in different cpp file.

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.
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

How to access device in different cpp file.

Post by Cube_ »

So as I abandoned my last issue I've refactored my code, however due to a reasonably complicated dependency chain I'm a tad stuck.

I create my device in the main function as one typically would, but I need access to the scene manager from a member function of a class in my voxelnode.cpp file (specifically the chunk function).

A slight caveat though, the class cannot be called directly as it's supposed to only be called by the chunk manager.
I could move the chunk class to voxelnode.h but then I'd have to move the chunkmgr and the block class there as well, further I'd have to move my enumerator of available blocks, all of these are things I'd rather hide behind a neat interface (the chunk manager).

In theory I could use a global pointer to the device, however this is both bad practice and I still can't think of any way to access that pointer from my voxel node (creating it in the config header causes each file to compile neatly but they fail at the linking step due to the device being declared twice, this is with header guards mind you).

To clarify the issue.
What would be a good way to allow access to the irrlicht device from multiple files? (the function that calls the chunk manager is void and the compiler claims on trying to pass the device as a parameter, not that I expected that to work anyway)
do note that forward declaring any of the classes happens to be impossible in this case (invalid use of an incomplete type).

Seeing the getSceneManager() function gets the location of the scene manager my plan of using it should work fine once I can somehow get access to the device from this file (99% sure that generating two devices is a horrible idea, further I still need access to the device in main.cpp so the problem really only moves if I move it to voxelnode.cpp)


In theory I might be able to create an intermediary render function that takes the chunk output as a parameter and which can then be called from my main thread and which then further passes the data along to the main thread but that sounds like a weird hack at best (further I still only move the problem, if I call render(mesh) in chunk::createMesh then I still need to get that to int main, which I don't see any way of doing).
Either way that's enough 11 pm coding for now, it's not getting me anywhere.
"this is not the bottleneck you are looking for"
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: How to access device in different cpp file.

Post by mongoose7 »

If A knows Irrlicht and B doesn't and C does, and logic flows form A to B to C, the declare device to be a void pointer in B.
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: How to access device in different cpp file.

Post by thanhle »

1) You can create a class that hold the global objects together.
That class will contain the driver, your manged list of objects etc.
e.g. When you first initialise your engine, create an instance of that class. Or otherway around that class contain your render engine.

Then pass that object into your other classes?

But you wouldn't want to pass that object every where. If you want some part to be portable, then you would only pass in the device or the driver?

Regards
thanh
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

It works... sorta

Post by Cube_ »

Okay, so now it works... sorta.

RUN FINISHED; Segmentation fault; core dumped; real time: 420ms; user: 80ms; system: 70ms

main.cpp

Code: Select all

 
void *pDevice;
 
int main( void )
{
//snip
 
    IrrlichtDevice *device = static_cast<IrrlichtDevice*>(pDevice);
    device = createDevice(EDT_OPENGL, dimension2d<u32>(800,600),16,false, false, false, 0); 
    
    if(!device)
        return 1;
    
    setPointer(pDevice);
//snip
}
voxelnode.h

Code: Select all

#ifndef VOXNOD_H
#define VOXNOD_H
#include "config.h"
 
void setPointer(IrrlichtDevice* chocolate);
 
 
#endif
voxelnode.cpp

Code: Select all

IrrlichtDevice* vDevice;
//snip
 
printf("\n\n INITIATING MESH CREATION LOGIC \n\n");
    video::SColor c(255, rand() % 256, rand() % 256, rand() % 256);
    scene::SMesh *mesh = new scene::SMesh();
/* Insert nested for loops here */
if(blocks[x][y][z].isActive() == false)
                {
                    continue;
                }
else
                {
                    video::S3DVertex vertices[4] =
                    {
 
                        video::S3DVertex(-2,+2,-2, 0,1,0, c, 0,1),
                        video::S3DVertex(-2,+2,+2, 0,1,0, c, 0,0),
                        video::S3DVertex(+2,+2,+2, 0,1,0, c, 1,0),
                        video::S3DVertex(+2,+2,-2, 0,1,0, c, 1,1),
                    };
                    u16 indices[6] = {0,1,2,2,3,0};
                    
                    for (u32 i=0; i<6; ++i)
                    {
                        scene::IMeshBuffer *buf = new scene::SMeshBuffer();
                        buf->append(vertices + 4 * i, 4, indices, 6);
 
                        buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
                        buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
                        buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
                        buf->getMaterial().setFlag(video::EMF_WIREFRAME, false);
                        
                        mesh->addMeshBuffer(buf);
                        buf->drop();
 
               //I had a debug message here but since this segment runs 64^3 times each time chunk() is called and it is called a total of 8 times right now... yeah, it wasn't feasible to keep it. However it gets this far and then crashes, it should create one mesh per chunk and apparently appending the mesh to my Smesh works but it never gets any farther than this point on the 64^3rd runthrough (maybe I caused an overflow?).
                    }
                }
    //It never gets to this debug message, it segfaults before it gets here and I can't figure out why.
    printf("\nFETCHING SCENE MANAGER\n");
    ISceneManager* mgr = vDevice->getSceneManager();
    printf("\nFINALIZING MESH\n");
    scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
    printf("\nCLEARING INTERMEDIARY MESH");
    mesh->drop();
    printf("\nSCALING AND NORMALIZING MESH");
    scaleMesh(anim_mesh, scale);
 
//snip
 
void setPointer(IrrlichtDevice* chocolate)
{
    printf("\n\nSTARTING CHUNK MANAGER\n\n");
    vDevice = chocolate;
    chunkMgr();
}
Walking through the code, I create a void pointer, I create the Irrlicht device.
I then do a static cast on the void pointer making it point to the Irrlicht device and pass it to the setPointer() function.
It then sets the IrrlichtDevice pointer declared at the top of voxelnode.cpp into the pointer passed from main.cpp
then I proceed with initializing my chunk Manager (which generates 8 chunks as expected), the chunks each create their mesh and it crashes as per the comments in the code.

This is technically a new issue, I am probably just misunderstanding how to properly append meshes together.

It should be some 1,048,576 vertices generated (64^3 * 4), not feasible for production but my logic for only generating the relevant faces has been disabled until I can get mesh to generate *at all*.

I added a simple counter to it and it seems to segfault at 384 runs through it. (every time)
Seeing it's a consistent point of failure I assume it is an overflow?
"this is not the bottleneck you are looking for"
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: How to access device in different cpp file.

Post by mongoose7 »

What on earth is this?

Code: Select all

buf->append(vertices + 4 * i, 4, indices, 6);
'vertices is an array of *only* 4 elements. If i > 0 you fall off the edge of the world!
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

mmm that might indeed be where my issue lies, I used to have a block that generated an entire cube (that's however not efficient as that could in worst case return 5 faces that aren't visible), I must've forgotten to change the allocator (it still works for anything less than 384 faces though which is probably why I didn't catch it in my limited testing)

However it also fails if I do
ISceneNode *node = mgr->addCubeSceneNode(1.0f);

I probably have an issue with my glob of pointers to get the device but I don't even know how to debug it.


However even when I fix the aforementioned array of vertices back to a full cube (including restoring all the face data generation) it still explodes at 384 though.
I had previously tested it with a set of 150 cubes and that worked fine, I'm a tad perplexed. (the fact that I'm coding in the evening probably isn't helping).
"this is not the bottleneck you are looking for"
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

UPDATE:
I placed my tracking code in the wrong area (one bracket too high up the chain) and it generated 6 entries per loop.
corrected results below
At varying chunk sizes these are the results:
chunk size
16 = 16 loops before crash
32 = 32 loops
64 = 64 loops
128 = 139 loops //weird, the loop count is higher than the chunk size amount
256 = 288 loops //weird, the loop count is higher than the chunk amount
4096 = 4304 loops //weird, the loop count is higher than the chunk amount
8192 = 8192 loops
65536 = 65536 loops
262144 = 262144 loops //this is the proper amount supposed to be generated in one chunk so the mesh can hold this amount of data, I'll thus discount the probability of an overflow.

This is highly perplexing, we can safely assume that my mesh isn't overflowing since it can handle a varying amount of loops.
Now the only thing that perplexes me is how this is happening.

The two bugs I can find based on my debugging:
it crashes as soon as it generates the first layer of the mesh, this is bad.
it crashes once it tries to get the device, this is even worse.


running it in GDB tells me this
Program received signal SIGSEGV, Segmentation fault.
0x000000000040792e in block::isActive (this=0x500000005) at VoxelNode.cpp:76
76 return b_active;


However this makes no sense as the only line there is
return b_active;

b_active is a boolean that's set to true in the block() constructor as such:
b_active = true;

The crash most likely actually lies somewhere else.

a strace returns nothing of value.
I wonder if valgrind can help me?
"this is not the bottleneck you are looking for"
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

Here's a weird conundrum:
Changing
return b_active;
to
return true;

solves this crash bug.
this is not feasible for a bunch of reasons, a) I need to be able to set blocks active/inactive programmatically and b) what?


b_active is *always* true regardless so I do not understand why it crashes.

Code: Select all

printf("\n\n GENERATING BLOCK DATA\n\n");
    b_blocks = new block**[CHUNKSIZE];
    for(int i = 0; i < CHUNKSIZE; i++)
    {
        b_blocks[i] = new block*[CHUNKSIZE];
        for(int j = 0; j < CHUNKSIZE; j++)
        {
            b_blocks[i][j] = new block[CHUNKSIZE];
            createMesh();
That's the only code that ever calls it, it's a nice nested loop which generates a 3D array, nothing in particular to write home about and it works when I set it to true, but it only works for the first layer when I use b_blocks to determine it, even though b_blocks is never set to anything else, it's always true and even if it wasn't it should still go through the loop regardless (just won't generate any mesh if that happens).

This is a weird bug.

However it's not quite as important as my device causing a segfault, the logic for how I do that is in one of the posts above but I'll repost it here anyway (excl. code snippets)
Walking through the code, I create a void pointer, I create the Irrlicht device.
I then do a static cast on the void pointer making it point to the Irrlicht device and pass it to the setPointer() function.
It then sets the IrrlichtDevice pointer declared at the top of voxelnode.cpp into the pointer passed from main.cpp
then I proceed with initializing my chunk Manager



Debugging further I notice that it also crashes if isActive ever returns false, which is odd.
I check for that, I'll look over that logic, either way it's weird that 128-4096 run more runs than they should before crashing.
This check is of course done by this block

Code: Select all

                if(b_blocks[x][y][z].isActive() == false)
                {
                    continue;
                }
Which is weird because it should work.
But it doesn't.
If I change continue; to printf("\nfail\n"); it does work however.
Which is weird.
because continue should just break the if and continue on the next iteration of the loop and now my head hurts holy what?


also disregard my above note, while it gets much farther on the generation there might still maybe be an overflow because this:
16384

Program received signal SIGSEGV, Segmentation fault.
0x0000000000407d1a in chunk::createMesh (this=0x8a1b18) at VoxelNode.cpp:144
144 if(!b_blocks[x][y][z].isActive())


16384 is of course a lot smaller than 64^3
*this happens with any chunk size, 4 returns 32 loops but the chunk should have 64 entries.
chunk size 1 compiles fine because..... well it's one cube.

chunk size 2 returns a crash as expected.


with a chunk size of 1 I can at least get the debug info from the second crash
1


OBTAINING DEVICE POINTER


Program received signal SIGSEGV, Segmentation fault.
0x00000000004085f2 in chunk::createMesh (this=0x8a1b78) at VoxelNode.cpp:372
372 mgr = vDevice->getSceneManager();
"this is not the bottleneck you are looking for"
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

UPDATE:
It seems to be highly unpredictable as to where it crashes.
It's very likely to crash at 16384 (at least 90% based on my test runs), incidentally a perfect 16th of a chunk.
However I've seen it as low as half of that (8192) and in the 12k range.
the highest it's ever gotten is 24576.

I also know this is not a memory issue. (based on having 4gb of free ram and this shouldn't even use 100, and it doesn't at any point where it crashes peak has been 55mb with debugging information).
"this is not the bottleneck you are looking for"
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to access device in different cpp file.

Post by CuteAlien »

Too much too read right not. But some comments after quick-reading over parts of it:
You don't need a void pointer. You really nearly never need a void pointer. The only reason to ever use a void pointer is if you work with types you don't know. In this case you work with an IrrlichtDevice* so you know the type exactly and there is no reason whatsoever to use a void pointer. Well, maybe one reason - you haven't learned yet about forward declarations in which case you might abuse void pointers to get around compiler errors in a really horrible way :-)

You have a few way of getting access to a pointer from another file:
a) You make your pointer global. Which works by using the extern keyword in the header and initializing it in one(!) .c/.cpp file. It's not a good solution but works.
b) You pass the pointer which that other class needs to that class. So that class takes for example a IrrlichtDevice* in it's constructor. Or it has a setIrrlichtDevice(IrrlichtDevice* device) function which you call. And then that class saves the pointer in the class members. That clean and works. One disadvantage is that you have be careful to update the pointer in all classes which receive it when you create a new device one day (you likely never need that).
c) You have global class which has a pointer to the IrrlichtDevice. Similar to a) - just hiding it a little bit. It's a lazy solution, but I admit I also do that once in a while. Advantage - it looks a little bit cleaner as you at least access the pointer usually through a getDevice function then which gives you a small wrapper. Disadvantage - basically you still have a global. Which means any part of your program can access everything in Irrlicht.
d) You pass along one class which holds a pointer to IrrlichtDevice. Let's call it the application class. Somewhat nice as the device-pointer is then in a single places in your application. Which is good. The bad part is - you probably pass along that application class all the time to nearly all your classes. Which gives all your classes again too much access to everything.
e) You only pass along those pointers to each class which they exactly need.Which means - you rarely never pass on IrrlichtDevice* itself. But for example IVideoDriver*, ISceneManager* and IGUIEnvironment*. That is the cleanest way in an OO sense. As you can see now from the interface of each class exactly which other classes it really needs. The disadvantage is - it's the most typing. And you still have to ensure to update any of those pointers if they ever change (which they probably won't in this case).
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
polylux
Posts: 267
Joined: Thu Aug 27, 2009 12:39 pm
Location: EU

Re: How to access device in different cpp file.

Post by polylux »

Is there a reason noone's mentioned a Singleton yet?
beer->setMotivationCallback(this);
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

CuteAlien, I was hoping a global wouldn't be required but it seems it is.

b) is impossible due to the hierarchy of classes (at least in a clean manner, I could hack it in but that's bound to cause a bunch of issues, including giving most everything access to Irrlicht anyway)

d) is interesting but fundamentally incompatible with my current design, at least in a clean manner.


As for forward declarations, I tried forward declaring the various classes to implement solution d) but the only way to forward declare the classes that need it is to move these things from my cpp to the relevant header:
block enumerator (do not want to grant public access to this, it should remain hidden)
my block class
chunk class
chunk manager class

The only thing I currently forward declare to give access outside the relevant scope is my interface between the chunk manager and the rest of the game.

and I really don't think passing a pointer from
main > chunk manager interface > chunk manager > chunk
is a clean solution.
I'll go with the global then (even though I was hoping I could get around that by using pointer magic to throw a pointer from main to voxelnode.cpp and have it only be global within the scope of my voxels)
"this is not the bottleneck you are looking for"
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

Okay.
Now that works, I can successfully play with the scene manager and allocate data.

Now, how much memory does addCubeSceneNode use? I'm using it to quickly visualize the data as my mesh builder crashes (and I don't even know why). at a chunk size of 8^3 it takes 51.5mb, at 16^3 it takes 1.4gb (I'd expect it to use no more than 400ish mb, 16^3 is only 8x larger than 8^3) and at 64^3 it crashes after eating all my memory. (which it does not if I use my normal mesher and build one mesh per voxel, however I need to generate one mesh per chunk. ah well, I'll have to keep hacking at that)
"this is not the bottleneck you are looking for"
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to access device in different cpp file.

Post by CuteAlien »

Just a note about forward declarations. You need them when you want to use a pointer or a reference to a class which is not known otherwise. There's no other situation really. In such a case you can forward declare a class/struct so the compiler knows it's a valid class/struct type. And it can then be used because all pointers have the same size so the compiler knows how much memory to reserve for such a variable.
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
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: How to access device in different cpp file.

Post by Cube_ »

I'm starting to think my build environment is insane.

Code: Select all

void chunk::createMesh()
{
    video::SColor c(255, rand() % 256, rand() % 256, rand() % 256);
    for (int x = 0; x < CHUNKSIZE; x++)
    {
        for (int y = 0; y < CHUNKSIZE; y++)
        {
            for (int z = 0; z < CHUNKSIZE; z++)
            {
                if(!b_blocks[x][y][z].isActive())
                {
                    printf("\nfail\n");
                }
                else
                {
                    printf("test %d %d %d \n",x,y,z);
                    ISceneNode *node = smgr->addCubeSceneNode(1.0f, 0, -1, core::vector3df(x,y,z));
                    node->setMaterialFlag(video::EMF_WIREFRAME, true);
                }
            }
        }
    }    
}
One would expect that to compile cleanly, it does.
It produces this log:

Code: Select all

GENERATING BLOCK DATA
 
test 0 0 0 
test 0 0 1 
test 0 0 2 
test 0 0 3 
test 0 0 4 
test 0 0 5 
test 0 0 6 
test 0 0 7 
test 0 1 0 
test 0 1 1 
test 0 1 2 
test 0 1 3 
test 0 1 4 
test 0 1 5 
test 0 1 6 
test 0 1 7 
test 0 2 0 
test 0 2 1 
test 0 2 2 
test 0 2 3 
test 0 2 4 
test 0 2 5 
test 0 2 6 
test 0 2 7 
test 0 3 0 
test 0 3 1 
test 0 3 2 
test 0 3 3 
test 0 3 4 
test 0 3 5 
test 0 3 6 
test 0 3 7 
test 0 4 0 
test 0 4 1 
test 0 4 2 
test 0 4 3 
test 0 4 4 
test 0 4 5 
test 0 4 6 
test 0 4 7 
test 0 5 0 
test 0 5 1 
test 0 5 2 
test 0 5 3 
test 0 5 4 
test 0 5 5 
test 0 5 6 
test 0 5 7 
test 0 6 0 
test 0 6 1 
test 0 6 2 
test 0 6 3 
test 0 6 4 
test 0 6 5 
test 0 6 6 
test 0 6 7 
test 0 7 0 
test 0 7 1 
test 0 7 2 
test 0 7 3 
test 0 7 4 
test 0 7 5 
test 0 7 6 
test 0 7 7 
 
RUN FINISHED; Segmentation fault; core dumped; real time: 340ms; user: 70ms; system: 60ms
Why do I find this odd?
Well, first of all the Y and Z dimensions generate fine (producing a nice, 1 block thick wall), second of all it works fine if I generate the cubes the exact same way from within the chunk classes constructor but not from within chunk::createMesh()

This is of course a simplified member function to debug my crashing issue.
The only thing I can think of is that it doesn't like nesting loops.
chunk is a constructor of three nested for loops generating the block data, calling the createMesh function to actually build the mesh at the same time.
In theory this should work fine, three more nested loops shouldn't cause an issue but it seems to do just that.

I don't even know how I would debug this, it just shouldn't happen.
essentially this is what it'd end up looking like

Code: Select all

for
{
    for
    {
        for
        {
            for
            {
                for
                {
                    for
                    {
                        if
                        //print log entry
                        else
                        create cubes
                    }
                }
            }
        }
    }
}
I don't think this should cause a crash. I honestly don't see why it crashes.

FYI it still crashes at the same place with the scene node allocation gone.

EDIT: Interestingly it gets farther with my intended chunk size of 64

Code: Select all

//snip, I don't think you want a log of thousands of entries listing cubes created
test 1 18 48 
test 1 18 49 
test 1 18 50 
test 1 18
RUN FINISHED; Segmentation fault; core dumped; real time: 460ms; user: 70ms; system: 110ms
 
And it isn't unreasonably slower, once I can fix this crash bug I can allocate my meshes more efficiently than creating cube scene nodes and the times should keep under 300ms for a full chunk (which is acceptable)


EDIT 2: Apparently the outcome is unpredictable for 64 blocks, first of all the result always differentiates (aside from the segfault, that's guaranteed)
but more importantly the final entry always cuts off at a different place (it's always cut off however).

Code: Select all

test 4 53 54 
test 4 53 55 
test 4 53 56 
test 
 
EDIT 3: I'm pretty certain this concludes my build environments sanity (insane): http://pastebin.com/KG9d7zc9
that is the offending logic condensed down to its own little program, it crashes even faster.
Last edited by Cube_ on Fri Mar 06, 2015 5:15 am, edited 1 time in total.
"this is not the bottleneck you are looking for"
Post Reply