Manipulate child meshes

Blitz3D Forums/Blitz3D Beginners Area/Manipulate child meshes

Gazza69(Posted 2013) [#1]
I have downloaded a free Apache gunship model in 3ds format.
I don't think it has any animation (no animation file)
It has 8 children when I used CountChildren.
I am loading the mesh using loadanimmesh("chopper.3ds")
I then want to manipulate child1 and child2 (tailblade and rotarblade)
I can do this by setting variables :
tailblade = getchild(chopper,1)
rotablade=getchild(chopper,2)

I then use :

Moveentity chopper, 0,0,1
turnentity tailblade, 0,10,0
turnentity rotarblade, 0,0,10

this moves the chopper nicely and turns the blades in.

I have tried to take this one step further and set up a type for the chopper:

Type helicopter
field body
field tailblade
field rotarblade
end type

I have then made a new global variable:

Global chop1.helicopter

and I use this function (below) to make the chopper:

loadchopper()
=========================================

Function loadchopper()
chop1.helicopter = New helicopter


chopmodel =LoadAnimMesh("gunship.3ds")
ScaleEntity chopmodel, 3,3,3
chop1\ID = CopyEntity(chopmodel)
chop1\rotorblade =GetChild(chopmodel,1)
chop1\tailblade=GetChild(chopmodel,2)
FreeEntity chopmodel
PositionEntity chop1\id,30,40,10
RotateEntity chop1\id,90,0,0
End Function



The first example works, but when I set it up as a type, the chopper still moves in the correct direction, but the blades don't rotate. No errors are reported.


Yasha(Posted 2013) [#2]
That's because you've set chop1\rotorblade and chop1\tailblade to the child components of the original entity, but you've set chop1\ID to a newly copied entity which has its own copies of the child components. After you free the original, the child entities reference by chop1\rotorblade and chop1\tailblade no longer exist.

So you need to get the children of the specific entity you intend to use - of the copy, if you want to use a copy. Try GetChild(chop1\ID, 1) instead.

Last edited 2013


Gazza69(Posted 2013) [#3]
Oh yes, that works. I can see how that makes sense.
But why wouldn't I get a MAV when manipulating the chop1\rotorblade if it no longer existed after freeing the entity/child it pointed to?


Yasha(Posted 2013) [#4]
While getting a MAV always means something has gone wrong, something going wrong doesn't always mean an error will be generated.

Due to an intricacy of how memory is allocated by the OS, a B3D entity doesn't immediately become invalid once it's freed, and most likely will never become invalid at all (the memory will be a priority area for reuse). You can therefore continue to use simple entity commands like EntityX, TurnEntity etc. that only manipulate the base entity struct, as long as this is the case. It's actually a (ridiculously minor) potential exploit, since if anything else were ever allocated over the same area as the old entity, you could use commands like EntityX to read data from it.

The reason for this is the fact that the OS has no understanding of "objects" (in the memory sense, not the 3D sense). It would be grossly inefficient to expect the OS's "real" memory management system to respond every time a program needs a new 16-byte block of memory. Instead, the OS allocates only entire "pages", which on most current operating systems are never less than 4KB, and passes these to the program; the program than allocates space out of the pages (for big objects, spanning many pages) using a higher-level memory library utility such as C++'s "new" or the famous "malloc", which maintains various hidden internal information structures to keep track of which parts of which pages are currently in use; so when you call a Free command, what that actually does is give the memory back to the malloc library, which is still within your program; the library will only return memory to the system if it can return complete empty pages. Most likely it will never do this since those pages will just get reused the next time an object needs to be allocated anyway.

A MAV can only be detected when the OS intercepts an attempt to access memory that the application hasn't been given permission to use. This means the memory address in question needs to map to somewhere that would be on an unallocated page from that program's perspective. Because of the above process where anything that was once an entity is almost certainly still on an allocated page, it's out of the OS's hands and won't be reported as a MAV. There are other ways to check for object validity, but in general they're incredibly inefficient and would ruin your program's performance (this is one reason why there's no "EntityExists"; the other is that if you ever need it, you're doing something terribly wrong anyway).


Gazza69(Posted 2013) [#5]
Thanks for response Yasha, appreciate it. I can follow what you say, gets a bit in depth for my understanding, but I can follow the logic. I was thinking FreeEntity is totally deleting the object, I can see that is not the case now.
Nonetheless, I will avoid using them once I have used FreeEntity.

Cheers

Gazza