#820 posted by necros on 2012/08/05 20:43:04
Dunno if anyone has mentioned this before (Preach maybe?) but I've been using a lot of multi-entity setups these days and cleaning up after them has become rather annoying so I used this trick to simplify things:
void(entity e) remove_builtin = #15;
.void() removeFunction;
void(entity e) remove =
{
local void() _removeFunction;
entity tempSelf;
if (e.removeFunction)
{
_removeFunction = e.removeFunction;
e.removeFunction = SUB_Null;
tempSelf = self;
self = e;
_removeFunction();
self = tempSelf;
}
remove_builtin(e);
};
Create a wrapper for the remove builtin that first checks if a .removeFunction is set, and if so, run it.
Then, I just create a unique function for each multi-entity that takes care of any child entities.
Note how we first save a reference to the .removeFunction() before clearing it. This is to prevent some recursive removeFunction running where (if you are not careful) you remove a child entity that then removes the parent, that then removes the child... etc...
This makes sure it only runs once.
ps, sorry about formatting.
Destructive
#821 posted by Preach on 2012/08/05 23:18:25
Works like a destructor in C++ (*), I like the recursion guard you put in there, I don't remember seeing that before.
Another place where this can be helpful is if you have some kind of linked-list structure, where removing an entity would break the chain. You can set a removeFunction which repairs the list before and after the entity which is getting removed.
* How long can it be before we get a QC++ compiler bringing the full power of object orientation and inheritance to our favourite game?
Loading MDL Files
#822 posted by necros on 2012/08/07 06:28:21
Trying to load .mdl files with java following this: http://tfc.duke.free.fr/coding/mdl-specs-en.html
For the most part, I got the data in fine, but for some reason, there seems to be a few extra bytes AFTER the frames that I don't know what to do with.
The number of bytes isn't consistent either, sometimes it's 10 bytes, other times it's 9 or 8.
Obviously, this screws up the next frame from loading properly because all the bytes are offset by however many were left over.
I tried just doing the dumb thing and skipping over these extra bytes after loading a frame, but the number of extra bytes can change within the same model.
Is this a real thing (extra bytes between frames) or am I just messing something up?
#823 posted by mh on 2012/08/07 07:44:36
Extra bytes between frames isn't normal. Possible that your struct sizes are being padded out to some alignment? I don't know Java so I'm not certain if it even does that, but it's the only off-the-top-o-me-head explanation I can think of.
#824 posted by necros on 2012/08/07 07:59:19
Thanks, I was just looking for confirmation that there are no extra bytes. :)
Java doesn't have structs or any of that, so I'm just reading everything in byte and byte and converting things to big endian ints and such.
I'm sure I'm just reading something in wrong or I missed something.
Gotchas
#825 posted by Preach on 2012/08/07 12:19:36
One of the things to watch out for is where there are mdl_vertex_t being loaded to define the bounding boxes of the frames and the like. Make sure you're reading the vertex normal in all of those places, even though it's not used.
#826 posted by necros on 2012/08/07 20:42:16
For the first frame, the data seems to be fine up to (at least that I can easily check) the frame name.
I parse each byte as a char until I get to the first byte that is 0, then I start loading vertex objects.
The problem seems to be somewhere during the vertex loading.
I'm using a 5 frame model with 5 verts.
Looking at the file itself, I see 48 bytes between one frame name and the next, so it looks like each frame is 48 bytes long. (the frame data actually starts 12 bytes before the name, there's one int (4 bytes) and 2 mdl_vertex_t (2 * 4bytes))
The mdl_vertex_t struct has an array of 3 unsigned chars and then a single uchar, so that means each vertex should be 4 bytes long.
So with 5 verts, that should mean that all the vertex info should be 5 * 4 = 20 bytes.
Take those 12 bytes mentioned above and we have 32 bytes. The name is "POLY1" so that should be 6 bytes for the name (including \0).
So in total that's 38 bytes and then 10 bytes left over.
#827 posted by necros on 2012/08/07 20:47:00
hm.. ok, seems like typing it out helped me see the problem...
Looks like the String for the frame name is ALWAYS 16 bytes, not until the next 0 value. It loads in some junk characters but that explains the 10 byte offset (16 - 6).
That's really bizarre.
#828 posted by necros on 2012/08/07 20:58:41
actually, I guess it sort of makes sense.
c just stops reading strings when it reaches the first \0, but I guess they didn't want to bother with a dynamically allocated char array so those junk bytes are actually whatever was on the guy's memory when he saved the file...
Yup
#829 posted by Preach on 2012/08/07 21:12:49
You have permission to zero all of that out nicely when you export though! Also, don't forget to test your code with grouped frames and grouped skins before you're through - it always seems to be going so well until that point...
#830 posted by necros on 2012/08/07 22:19:38
I wasn't really going to bother with that for now.
Mostly, I just wanted to redo that "qcStarter" program I made so you could load a model and generate some basic monster code complete with a spawn function.
But now I'm thinking it'd be pretty cool to make a modern mdl editing program.
#831 posted by mh on 2012/08/08 01:00:04
c just stops reading strings when it reaches the first \0, but I guess they didn't want to bother with a dynamically allocated char array so those junk bytes are actually whatever was on the guy's memory when he saved the file...
Yup, that's it. The struct in the C code is defined as follows:
typedef struct {
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
char name[16]; // frame name from grabbing
} daliasframe_t;
Reason why is when loading an MDL you can just load the entire file into a single buffer, then walk through the data setting and incrementing pointers as needed. If every daliasframe_t is the same size the job becomes much easier.
Same basic principle applies to other model data that contains a string name; e.g. textures have a fixed 16 char array for their names.
#832 posted by necros on 2012/08/08 01:24:32
Makes sense, they would design the format to make it easy on themselves, not some guy digging into it 15 years later. :P
Now to see if I can draw it to screen!
I think understanding exactly what the heck is going on with the so called 'compressed coordinates' is going to be the really hard part. o.0
Hahaha
#833 posted by necros on 2012/08/08 01:37:30
This Is Interesting
#834 posted by RickyT33 on 2012/08/08 01:40:40
I always wondered what the algorithm was for drawing point to point in 3D.
Also I'm stunned that I am following this. It actually makes sense to me(!) now that I can program a little.
#835 posted by mh on 2012/08/08 01:58:44
they would design the format to make it easy on themselves
...and they even failed at that!!! http://www.team5150.com/~andrew/carmack/johnc_plan_1997.html#d19970707 (section beginning "anatomy of a mis-feature").
well, it was supposed to be a fiend...
It's real close though, and a whole ton better than my first attempt at doing this with C# 8 or so years back.
#836 posted by necros on 2012/08/08 02:19:08
http://necros.slipgateconstruct.com/temp/nowthatsafiend.jpg
Silly mistake... tried reading in verts on the frames directly. :P
Oh Thanks For That Link
#837 posted by necros on 2012/08/08 02:20:12
It's nice that that .plan stuff is archived. I never had internet back then (plus I was too young) but that seems very interesting now. :)
#838 posted by mh on 2012/08/08 02:36:41
Good stuff with the fiend. You gonna take this all the way and do texturing too?
The .plan archive is essential reading, it's a great window into the thinking behind why much of Quake is the way it is, and can be very informative for decisions of the "should I add/remove/change this feature?" kind.
Skinzz
#839 posted by necros on 2012/08/08 08:03:07
Good Job, Necros...
#840 posted by generic on 2012/08/08 13:24:43
I can see its eye in that shot :)
Heresy!
#841 posted by jt_ on 2012/08/08 14:13:18
Fiends don't have eyes.
Yes They Do!
#842 posted by negke on 2012/08/08 18:29:46
You guys don't do a whole lot of looking at things, do you?
http://www.lunaran.com/pics/fiends...
And now, shambler will argue that those aren't actually eyes:
Herp Derp
#843 posted by Shambler on 2012/08/08 18:32:40
#844 posted by Spirit on 2012/08/08 18:41:26
I thought those were nipples?
|