Multiple textures to different parts of a model: how?

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.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Multiple textures to different parts of a model: how?

Post by CuteAlien »

The problem isn't Irrlicht, but this are c++ issues.
I'm not sure if I catch everything, but here's a quick overview of problems:

1. Prepare your code when asking for help.

This code won't compile: ISceneManager* smgr = device->getSceneManager(;)
You see yourself what's wrong in this line, but my complain is a deeper one. When you ask for help in a forum you expect other people to invest time for you. And that's always a thing you should do only after you tried everything yourself and prepared for it. First step is to reduce the problem to the minimum. It should contain as little lines as needed to reproduce the problem and no more. That has 2 reasons. First to make it easier for other people to read your code. And second you divide your problem-space. Often you will find the solution already while doing that. It's a common debugging technique - one of our university profs called it divide&conquer.

You have posted much code here which doesn't belong to the problem. Like all your ini code which even depends on another file which we don't have. Just hardcode such stuff in forum questions. More stuff to kick out here: the input code, the sound-code, the skybox code and the gui-code. Once all that is gone you will have it easier yourself figuring out what's going on.

And make sure it compiles!

2. Variable definitions in a header. C++11 allows to do that a little bit inside classes, but aside from that just don't do it. Only put declarations in headers. Because this header is useless otherwise - you can't include it from different sources like that.

3. You put code in the global namespace. This is a bad thing to do in c++. And does not work like you expect at all.
Examples where you do that are: IrrlichtDevice *nulldev = createDevice(video::EDT_NULL);
or: unsigned char renderer=buf[0];
Code belongs either in classes or inside your main() function (or any classes or functions called from there).
Global initializations outside of main are a very hard and tricky topic. It's OK in very small programs to initialize a few global integers. But never call any code unless you have no other choice and really know what you do. And you have to be very good in c++ to know what the compiler will do in that case! Initialization order in the global namespace is a rather advanced topic. As an example what can go wrong - I suspect the lines above will not be called in the order they are written down, but the renderer line would likely run before the nulldev line.
In your case it means all your config values are likely filled with random values as the config is probably read after the buf assignments are done (dynamic code in global namespace runs after static initializations - but I'd have to debug myself to be sure if that's what the compiler does here).

TL;DR: Avoid code outside main. Put your code inside main().

4. Variables and arrays are not initialized with 0 in c++. So this loop here won't do what you think:
for (i=0; i<65535 && !mesh_buffer[0]; i++)
The chance that mesh_buffer[0] is 0 before that is very low. It will contain whatever the value of memory was at program start. Nearly random and usually _not_ 0. In other words - initialize all your variables!
In this case it's likely causing your crash by the way.

5. Don't work with static arrays in c++ unless you have a very, very good reason for it. They make your life unnecessary hard. Use dynamic arrays instead. Irrlicht has core::array or c++ STL has std::vector (they do more or less the same). Then you don't have to think about stuff like initializing array values or getting array-borders correct. You just 'push' new variables on it.

6. Lastly - really learn to use a debugger. It's easy, it's important and you will learn programming much faster once you know how to use it. With a debugger you can step through your code line-by-line and just see at any point what is going on. And don't worry - debuggers are not hard to use, it's as easy as pressing 3-4 function keys.
Well - nearly... with code in the global namespace it's not that easy - another reason to avoid such code.

OK - enough for now - I hope it helps you a little to get started.
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
Devil Master
Posts: 81
Joined: Wed Apr 23, 2008 8:47 pm

Re: Multiple textures to different parts of a model: how?

Post by Devil Master »

Foaly wrote:Yeah, I think mongoose7 is right.
But you can set the materials in the SceneNode:

Code: Select all

 
node[0]->setReadOnlyMaterials(false);
node[0]->getMaterial(0)->setTexture(0, duketexture);
node[0]->getMaterial(1)-> ...
 
I hope that works.
Almost. :)
I just had to change this

Code: Select all

node[0]->getMaterial(0)->setTexture(0, duketexture);
into this

Code: Select all

node[0]->getMaterial(0).setTexture(0, duketexture);
and it worked!
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Multiple textures to different parts of a model: how?

Post by CuteAlien »

Might work for now - but please - read my post. Your code is not correct, especially point 3 and 4 are clearly wrong.
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
Devil Master
Posts: 81
Joined: Wed Apr 23, 2008 8:47 pm

Re: Multiple textures to different parts of a model: how?

Post by Devil Master »

CuteAlien wrote:Might work for now - but please - read my post. Your code is not correct, especially point 3 and 4 are clearly wrong.
Point 3 contrasts to what the author of MDDClone-SDL told me when he saw an earlier version of my TADPSID code. He said that there was code in main that did not belong there, and I had to take it out for that part to be readily reusable, so I did.
CuteAlien wrote:In your case it means all your config values are likely filled with random values as the config is probably read after the buf assignments are done (dynamic code in global namespace runs after static initializations - but I'd have to debug myself to be sure if that's what the compiler does here).
Actually, the configuration file is read just fine and every value is what it should be.
CuteAlien wrote:This code won't compile: ISceneManager* smgr = device->getSceneManager(;)
Yes, that code won't compile, but that's not what I wrote. What I wrote is ISceneManager* smgr = device->getSceneManager();

Point 4... yeah. In retrospect, I should have used a do-while loop, so that the check is made after the initialization, instead of before.

Point 5: Yes, it makes sense, so I googled for an example of core::array usage, but it seems that my understanding of the syntax is wrong. I replaced:

Code: Select all

IAnimatedMeshSceneNode* node[65536];
with

Code: Select all

core::array<irr::scene::IAnimatedMeshSceneNode*> node;
but the program crashes as soon as it executes any line where node[0] (or any other element of the array) is used. If all lines where the array "node" is used are removed, it correctly displays an empty scene.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Multiple textures to different parts of a model: how?

Post by CuteAlien »

OK, sorry about the getSceneManager thing - that must has slipped in after I copied your code.
But about the rest...

When someone tells you the code doesn't belong all into main as that is not re-usable he didn't mean you should move it into the global namespace. What he likely meant to say was - don't put all your code into the main function _directly_. Use sub-functions and classes instead which are called. So you can create a function doSomething() which is called inside main(). Or another function doSomethingElse() which is called inside doSomething() which is called inside main(). And so on - that's all fine. As long as your code starts in main(). Also creating class objects in there is good (but not class declarations!). But what you do here is something else - you put code *outside of all* functions and classes. And code there follows some very special rules in c++. It runs _before_ main is called and the order in which it runs is rather complicated. Just trust me that it's not what you should do. In other programming languages this is the correct way to code, just not in c++. And even creating class objects from a library there is very bad - you simply can't know if it will work or not It can even work randomly as the initalization order is undefined for some cases. For example if the library does use a global variable your compiler can set that before or after that code runs and you have no guarantee what it will do.

If your config works you are basically lucky that the compiler decided to consider your variable assignments there as dynamic as well as the functions. I would have suspected it would consider it static for this specific situation... learn about that stuff one day in a few years - it all doesn't matter much for now - just avoid doing it! There are some very rare constructs in c++ where you will need the global namespace for code, but programmers avoid it like hell as it's very hard to get right. For now - just make sure all your code is inside functions. Doesn't matter if the functions are just functions (that's c-style coding) or if they are inside member-function (functions inside classes). But don't have code outside all functions!

I won't say much more about your config but I would recommend to take a look at example 25 in Irrlicht to see an example about how to do a config file in xml.

About using core::array - you have to push your new objects in the array first. The nice thing is you have then exactly as many objects in there as you actually need. So you don't have to allocate thousands and not even know which ones are used and which are not. You do that in your case with node.push_back( that_new_object_variable). It makes no big difference as long as you have only 1 node (you wouldn't even need an array), but once you have several objects it get's more comfortable. For example the array knows it's size, so you can do loops like: for (u32 i=0; i<node.size(); ++i) { node->doStuff(); }
Or you can remove elements in the middle and even has some automatic sorting. Check documentation for what it offers: http://irrlicht.sourceforge.net/docu/cl ... array.html
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
Devil Master
Posts: 81
Joined: Wed Apr 23, 2008 8:47 pm

Re: Multiple textures to different parts of a model: how?

Post by Devil Master »

After a long time, I've finally had time to work on this program again. So, CuteAlien, I followed your suggestions and moved my configuration code into a function that is called before the main loop.
I still have to get the hang of working with dynamic arrays, even though I can see their advantages, so I decided to postpone that part. Instead, I went on to work on the main character's movements... and I stumbled upon another problem,that occurs when it's accelerating or decelerating. Anyway, posting about it here would be off-topic, so I'm going to make another thread
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Multiple textures to different parts of a model: how?

Post by CuteAlien »

Devil Master wrote:I followed your suggestions and moved my configuration code into a function that is called before the main loop.
Wait, I didn't say it like that :-) I say move your code into functions. And have no code outside functions. But don't call those functions then _before_ the main loop. A function call is code - so it belongs again into functions. Call no code outside functions!

(there are some very rare exceptions to that, but I'm pretty sure you don't need those yet)
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
Devil Master
Posts: 81
Joined: Wed Apr 23, 2008 8:47 pm

Re: Multiple textures to different parts of a model: how?

Post by Devil Master »

CuteAlien wrote:But don't call those functions then _before_ the main loop. A function call is code - so it belongs again into functions. Call no code outside functions!
Huh? What? By "main loop" I mean the part of the main function that is enclosed by the condition "while(device->run())". The configuration function is called from the function called main(), but before the loop.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Multiple textures to different parts of a model: how?

Post by CuteAlien »

Ah ok, that's certainly fine :-)
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
Post Reply