Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » RLE sprites are rats!

This thread is locked; no one can reply to it. rss feed Print
RLE sprites are rats!
The Master
Member #4,498
April 2004
avatar

I don't think RLE sprites like me very much, or at least the ones that have been created from a sub-bitmap of a frame-strip.
I've tried several different ways to create a sprite class using data contained entirely within a datafile, and i can refine it so that it all works, but i am always stopped by a runtime error when I try to draw the rle sprite to a bitmap. It is a Null Reference exception, which occurs when you're trying to access a memory address that doesn't exist. But I have gone through my code hundreds and hundreds of times, and cannot find any problem with it. i have come here seeking advice. I have included my source code, which has the location of the error indicated with a big comment. And, i must note, that this error shows up not in my code but in rle.inl. So i wonder if it's a problem with allegro. But in other programs where I have not used the process of extracting several rle sprites from the same bitmap, rather having the sprites as separate entries in the datafile and simply saying sprite = (RLE_SPRITE*)datafile[FRAME001].dat;
While this would solve my problem, it lengthens the time considerably that i would need to create these datafiles. I prefer to have one single sprite strip with frame numbers and speeds attached as properties. View the datafile if you want, it isn't password-protected. Anyway, just have a look, and any advice would be greatly appreciated.

Source code:
http://www.freewebs.com/ikari734/Sprite_class.zip

We can only do what we feel is right each moment as we live it.

Peter Wang
Member #23
April 2000

FYI you don't need to put END_OF_FUNCTION() after every single function, only the ones that you intend to call LOCK_FUNCTION() with.

Secondly, xor is a C++ keyword so you can't use it as the name of a member variable.

Finally, the bug is possibly due to this:

std::vector<RLE_SPRITE> anim_data;

You'd want a vector of pointers to RLE_SPRITEs instead. After I made that change, it worked, except for one thing: using C++ destructors to unload datafiles, remove timers, etc. is asking for trouble. Don't do it. If you do do it, make sure that instances of the class are destroyed before Allegro is shut down.

The Master
Member #4,498
April 2004
avatar

ok, cool. so you put this on your own compiler and it animated that little sprite? With the megaman animation?
i'll check these changes, cheers.;D

We can only do what we feel is right each moment as we live it.

Peter Wang
Member #23
April 2000

I don't remember it animating, but at least there was a sprite there :-)

The Master
Member #4,498
April 2004
avatar

just out of curiosity, how would you recommend i use (vector).push_back()? Pointer to the data, or the actual data?

We can only do what we feel is right each moment as we live it.

BAF
Member #2,981
December 2002
avatar

Pointer.

The Master
Member #4,498
April 2004
avatar

I've made the adjustments, however, there must be a problem with how the information is stored in the vector for anim_t. I am certain RLE_SPRITE works fine, however the vector that holds all information (including the RLE_SPRITE information) must not be stored properly. I have added a little debugging dump function which prints out the names of the animations in the anim_t vector, and it shows stuff like:

1// animation-loading function output
2Loading CLIMB...
3Loading DASH...
4Loading DOUBLE_BLAST...
5Loading FIRE...
6Loading GRAPPLE...
7Loading HURT...
8Loading JUMP...
9Loading LOW_POWER...
10Loading RUN...
11Loading STAND...
12Loading SWORD...
13 
14// dump function output
15Sprite names:
16`
17`
18`
19`
20`
21`
22`
23`
24`
25`
26`

You see what I mean?
I think it has something to do with the way the function loads the information and stores it in the vector. Shown below:

1/* get one animation from one datafile. This function is called for every datafile entry loaded */
2void Sprite::GetAnim(DATAFILE *d) {
3 const char *data_prop;
4 int x;
5 
6 struct anim_t animation;
7 
8 data_prop = get_datafile_property(d, DAT_NAME);
9 if(data_prop != empty_string)
10 ustrcpy(animation.name, data_prop);
11 
12 // if we've hit an end of file
13 if(ustrcmp("GrabberInfo", animation.name) == 0)
14 return;
15 
16 logstr("Loading %s...", animation.name); // dump
17 
18 data_prop = get_datafile_property(d, DAT_ID('X','S','I','Z')); // frame width
19 if(data_prop != empty_string)
20 animation.w = atoi(data_prop);
21 
22 data_prop = get_datafile_property(d, DAT_ID('Y','S','I','Z')); // frame height
23 if(data_prop != empty_string)
24 animation.h = atoi(data_prop);
25 
26 data_prop = get_datafile_property(d, DAT_ID('F','C',' ',' ')); // frame count
27 if(data_prop != empty_string)
28 animation.frame_count = atoi(data_prop);
29 
30 data_prop = get_datafile_property(d, DAT_ID('T','B','F','A')); // speed or Time Before Frame Advance (in one-sevenths of a second)
31 if(data_prop != empty_string)
32 animation.frame_speed = atoi(data_prop);
33 
34 data_prop = get_datafile_property(d, DAT_ID('X','P','O','S')); // x-origin
35 if(data_prop != empty_string)
36 animation.xorigin = atoi(data_prop);
37 
38 data_prop = get_datafile_property(d, DAT_ID('Y','P','O','S')); // y-origin
39 if(data_prop != empty_string)
40 animation.yorigin = atoi(data_prop);
41 
42 for(x=0;x<animation.frame_count;x++) {
43 /* create the rle sprite from a sub-bitmap of a image containing
44 all the animations in a film strip */
45 animation.anim_data.push_back( get_rle_sprite( create_sub_bitmap( (BITMAP*)d->dat, x*animation.w, 0, animation.w, animation.h ) ) );
46 }
47 
48 // store the pointer to the animation data in the vector
49 animations.push_back(&animation);
50 
51 return;
52}

If you need to see the rest of the code it is has been updated, and is here:
http://www.freewebs.com/ikari734/Sprite_class.zip

If there is anything more i should change, please let me know.

cheers, and I'll put your name in the credits.

We can only do what we feel is right each moment as we live it.

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

animation.anim_data.push_back( get_rle_sprite( create_sub_bitmap( (BITMAP*)d->dat, x*animation.w, 0, animation.w, animation.h ) ) );

Holy memory leak batman :o

as for the name problem.. what does your animation class/struct look like? is "name" allocated some space, statically, dynamically?

edit: I looked at your source, oddly I didn't see anything interesting, but you may want to check to see if you're overwriting some memory somewhere..

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Evert
Member #794
November 2000
avatar

As an aside, since this doesn't seem to be a problem with Allegro, could a friendly moderator move the topic to programming questions?

The Master
Member #4,498
April 2004
avatar

OK, let me take some time to explain the logic behind some of my programming decisions:

Quote:

animation.anim_data.push_back( get_rle_sprite( create_sub_bitmap( (BITMAP*)d->dat, x*animation.w, 0, animation.w, animation.h ) ) );

Holy memory leak batman

I know this is a dodgy memory leak. However, if I created a variable for the bitmap and the rle sprite, get the sub-bitmap, get the rle sprite from the sub-bitmap, and then add it to the RLE_SPRITE vector, it would store a pointer to the data right? If i were to reuse the rle_sprite or bitmap variables again, changing the data they contain, i would also be changing the data that would be percieved from reading the vector later on, would I not? If the vector contains pointers to the data and not actually the data itself, that is. Even still, destroying RLE_SPRITE or BITMAP structures inside a loop would be a bad idea as I'd have runtime exceptions all over the place. So as to avoid screwing up the information later on, I chose to do this as there would be no variables i would need to clear or destroy in a for loop or while loop (see the code). I have also considered using malloc instead of a vector for the RLE_SPRITE array, and even experimented with ZERO_SIZE_ARRAY, but when the program tries to read the information from the array, it returns a null reference exeption, always at the same place in the rle.inl file. I know it has no problem with Allegro, the pointers are just screwey in MY code. I don't think the malloc function works properly on my computer.

Quote:

I looked at your source, oddly I didn't see anything interesting, but you may want to check to see if you're overwriting some memory somewhere..

I just wanted to check if it is a bad idea to use a vector within a vector, like i've done. if so, would it be better to make the memory read-only after loading, to prevent any screw-ups? Is that even possible?

Quote:

As an aside, since this doesn't seem to be a problem with Allegro, could a friendly moderator move the topic to programming questions?

I agree this isn't a problem with Allegro, however, RLE_SPRITE structures have never been very cooperative with me, and i was wondering if anyone else had ever had this problem. But, Mr.Moderator, by all means move this wherever you like. I'm just after the answers.

Quote:

as for the name problem.. what does your animation class/struct look like? is "name" allocated some space, statically, dynamically?

This is the anim_t struct for holding the sprite information:

struct anim_t {
  char name[20];
  int frame_speed;
  int frame_count;
  int xorigin, yorigin;
  int w, h;
  std::vector<RLE_SPRITE*> anim_data;
};

As you can see, name is a set 20 character long string. All the rest are integers except for the anim_data. I would say that the vector storage of the RLE_SPRITE works. However, when the entire anim_t structure is written into the animation vector, a problem occurs. Either that or the whole thing screws up from the start at which point i would need to start writing the loading code from scratch, which makes up the bulk of the class. But hey, if I must, I must.

Just for the sake of explanation, i am incredibly bad at producing optimised code, and pretty much a hobbyist programmer. I've very little idea of how any of these things work except what I read in tutorials, and those ones only deal with integer and char vectors. I know how to use vectors, however this has never come up before.

We can only do what we feel is right each moment as we live it.

Go to: