Thread: [Tuxnes-devel] Smoother scrolling
Brought to you by:
tmmm
From: Ryan J. <pro...@ya...> - 2004-01-19 05:59:43
|
I'm new to the list, but I've been following the project for quite some time now. So please forgive me if I say something stupid ;-). I've noticed that on my hardware (a rather unimpressive PII-350 with nVidia RIVA TNT video card) that tuxnes' scrolling seemed kindof choppy. I started looking around the code, and found the resynchronize() function. By tweaking the value passed to usleep(), the scrolling became almost perfectly smooth. The one side effect I've noticed is that sound gets out of sync a bit more often than before, but not by much. I was considering writing a patch that would add a command-line option to decrease this delay by some amount (1 or 2 milliseconds seems to do it for me), but I was wondering if anyone might have a better solution. I'm not sure what unintended effects my hack might have. Any ideas? Also, has anything been committed to CVS in the last couple of months? There have been some postings to the list that indicate there has, but 'cvs update' doesn't download anything. Maybe I'm just smoking something... ;-) -- Ryan Jackson pro...@ya... |
From: Mike M. <che...@ya...> - 2004-01-19 09:21:28
|
I was chasing a simular problem, but I coulden't get any thing to work. I don't think it's correct to cahnge the usleep, as it's based on the NTSC standared. I.E. 16666 = 1 frame and if were n frames ahead 16666 * ( n - 1 ) is how long we wait. My solution was to eliminate the extra gettimeof day call. You only need one to get timing right. Here is how I normaly do video games... Loop () Read input <-- this is done inline with nes code and will not be called every frame. Adjust position of objects, calculate score, ect <-- this is all in nes code. Draw x = gettimeofday sleep frametime * ( x - y - 1 ) y = x <-- we now use another gettimeof day call for this endloop This is how tuxnes lookes... set_renderer_basetime Loop () { /* renderer.c */ set_timeframe /* This is my y = x */ call nes rom { /* These may happen in any order based on rom loaded */ Optionaly read input Optionaly play sound Change memory /* This includes drawing something */ } Draw contens of nes memory. set_frameskip resynchronize /* Notice time spent in resynchronize is not accounted for! */ } Here is the last commit. Mon Dec 8 16:46:33 2003 UTC (5 weeks, 6 days ago) by cheako RCS file: /cvsroot/tuxnes/tuxnes/emu.c,v retrieving revision 1.89 retrieving revision 1.90 diff -u -r1.89 -r1.90 --- tuxnes/tuxnes/emu.c 2003/12/05 23:05:37 1.89 +++ tuxnes/tuxnes/emu.c 2003/12/08 16:46:33 1.90 @@ -4,7 +4,7 @@ * Please see the README and COPYING files for more information regarding * this project. * - * $Id: emu.c,v 1.89 2003/12/05 23:05:37 cheako Exp $ + * $Id: emu.c,v 1.90 2003/12/08 16:46:33 cheako Exp $ * * Description: This file contains the main() function of the emulator. */ @@ -2116,7 +2116,7 @@ } /* enter the Game Genie codes */ - while (gamegenie != 0) + while (gamegenie > 0) { if ( gamegenie == 1 ) gamegenie = 0; if (verbose) fprintf (stderr, "------------------------\n"); @@ -2162,6 +2162,7 @@ fprintf (stderr, "Game Genie: value at %04X = %02X\n", address, MAPTABLE[address >> 12][address]); } + if ( gamegenie == 0 ) break; ggcode[--gamegenie] = '\0'; for (; gamegenie >= 2; gamegenie--) if ( ggcode[gamegenie-1] == ',' ) break; --- Ryan Jackson <pro...@ya...> wrote: > I'm new to the list, but I've been following the project for quite some > time now. So please forgive me if I say something stupid ;-). > > I've noticed that on my hardware (a rather unimpressive PII-350 with > nVidia RIVA TNT video card) that tuxnes' scrolling seemed kindof choppy. > I started looking around the code, and found the resynchronize() > function. By tweaking the value passed to usleep(), the scrolling > became almost perfectly smooth. The one side effect I've noticed is > that sound gets out of sync a bit more often than before, but not by > much. > > I was considering writing a patch that would add a command-line option > to decrease this delay by some amount (1 or 2 milliseconds seems to do > it for me), but I was wondering if anyone might have a better solution. > I'm not sure what unintended effects my hack might have. Any ideas? > > Also, has anything been committed to CVS in the last couple of months? > There have been some postings to the list that indicate there has, but > 'cvs update' doesn't download anything. Maybe I'm just smoking > something... ;-) > > -- > Ryan Jackson > pro...@ya... > > > ------------------------------------------------------- > The SF.Net email is sponsored by EclipseCon 2004 > Premiere Conference on Open Tools Development and Integration > See the breadth of Eclipse activity. February 3-5 in Anaheim, CA. > http://www.eclipsecon.org/osdn > _______________________________________________ > Tuxnes-devel mailing list > Tux...@li... > https://lists.sourceforge.net/lists/listinfo/tuxnes-devel __________________________________ Do you Yahoo!? Yahoo! Hotjobs: Enter the "Signing Bonus" Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus |
From: Jason D. S. <jd...@us...> - 2004-01-19 10:00:20
|
Mike Mestnik wrote: > I was chasing a simular problem, but I coulden't get any thing to work. I don't think it's > correct to cahnge the usleep, as it's based on the NTSC standared. I.E. 16666 = 1 frame and if > were n frames ahead 16666 * ( n - 1 ) is how long we wait. You don't want to usleep for a fixed amount of time, or you'll get *behind*. For instance if you sleep for 10 useconds and then do some calculations that take 5 useconds, your tick length is actually 5 useconds instead of 10 useconds as you wanted it to be. (Just using 10 as an example.) Instead you want to do your 5 usecond calculations then sleep for just the remaining 5 useconds. The easiest solution is to track the time of each tick. Use a timeval struct to tell when the next "tick" should occur. Then before sleeping figure out how long is left between now and then, and sleep for that long. Something like: struct timeval next, now; int usec; /* This is the only time we call gettimeofday on 'next'. After * this we just increment it. */ gettimeofday(&next, NULL); while (1) { next.usec += TICK_TIME; if (next.usec >= 1000000) { next.usec -= 1000000; next.sec++; } do_something(); gettimeofday(&now, NULL); usec = 1000000 * (next.sec - now.sec) + (next.usec - now.usec); if (usec > 0) usleep(usec); } In short, something like the attached patch should work. I haven't tested it, though. --- digression --- There are also external events that generally need to be handled. You generally shouldn't poll for these (however this is NES emulation so it's probably okay to be inefficient). I've generally written network code where you want to call select() while having a "tick" in place as well. This works great since select just takes the timeval struct as an argument. In GUI code you want to either get interrupts or pass the waiting off to a GUI function that can handle the interrupts directly. My experience is in GTK where you call a function to set a timer, then pass control back to GTK. While GTK has control it can do updates (like redrawing windows), handle events (if a key is pressed GTK will call your program's handler for that key), or handle the tick when the time comes (GTK will call your program's handler for that tick). SDL has something similar, although it's generally implemented with polling anyway. jason |
From: Jason D. S. <jd...@us...> - 2004-01-19 19:27:56
Attachments:
tuxnes.diff
|
Jason Dorje Short wrote: > Mike Mestnik wrote: > >> I was chasing a simular problem, but I coulden't get any thing to >> work. I don't think it's >> correct to cahnge the usleep, as it's based on the NTSC standared. >> I.E. 16666 = 1 frame and if >> were n frames ahead 16666 * ( n - 1 ) is how long we wait. > > > You don't want to usleep for a fixed amount of time, or you'll get > *behind*. For instance if you sleep for 10 useconds and then do some > calculations that take 5 useconds, your tick length is actually 5 > useconds instead of 10 useconds as you wanted it to be. (Just using 10 > as an example.) Well, that patch didn't work at all. The problem, though, is that you're tracking time in frames instead of in useconds. If you're half a frame ahead and you wait for one frame, then you'll be half a frame behind. Or if you wait until you're a frame and a half ahead and then wait a frame, you get uneven playing (2 frames in quick succession, then a wait before the next frame). This is hard to change because timeframe is a very different concept. But this patch may be a little better (now that I got tuxnes to compile). It's indistinguishable from the current behavior on my computer. jason |
From: Ryan J. <pro...@ya...> - 2004-01-20 07:53:29
|
On Mon, Jan 19, 2004 at 02:27:47PM -0500, Jason Dorje Short wrote: > This is hard to change because timeframe is a very different concept. > But this patch may be a little better (now that I got tuxnes to > compile). It's indistinguishable from the current behavior on my computer. It works great on mine... for about a minute, then the emu goes nuts. usec overflows and wraps around, becoming negative. Because of that, it thinks we've missed a whole crapload of frames, so it just resyncs over and over again. I've been playing with it a bit, but my patch has some problems (timing issues with some games). |
From: Jason D. S. <jd...@us...> - 2004-01-20 08:46:04
Attachments:
tuxnes-2.diff
|
Ryan Jackson wrote: > On Mon, Jan 19, 2004 at 02:27:47PM -0500, Jason Dorje Short wrote: > >>This is hard to change because timeframe is a very different concept. >>But this patch may be a little better (now that I got tuxnes to >>compile). It's indistinguishable from the current behavior on my computer. > > > It works great on mine... for about a minute, then the emu goes nuts. > usec overflows and wraps around, becoming negative. Because of that, it > thinks we've missed a whole crapload of frames, so it just resyncs over > and over again. It wraps around on frame 2148. Imagine that. In part this comes because of my overzealous desire to be accurate: I use (1,000,000 * frame) / 60 instead of (1,000,000 / 60) * frame but I guess the problem would kick in after about 60 minutes anyway, so it's just as well. This calculation needs to be done with an 8-byte "long long". (Side note: I didn't know a "long" was only 4 bytes???) Instead of using "long long" it would be nice to use sint64, if such a thing exists. SDL defines an Sint64, but not all of the code uses SDL, right? So, here's a new patch. Does this work better than the current behavior on your system? jason |
From: Ryan J. <pro...@ya...> - 2004-01-20 14:22:20
|
On Tue, Jan 20, 2004 at 03:43:48AM -0500, Jason Dorje Short wrote: > > but I guess the problem would kick in after about 60 minutes anyway, so > it's just as well. This calculation needs to be done with an 8-byte > "long long". (Side note: I didn't know a "long" was only 4 bytes???) I tried that myself, but forgot a cast, so the emu just hung. I got frustrated and gave up. I feel stupid now :-( > So, here's a new patch. > Does this work better than the current behavior on your system? Definately! Things look a lot smoother now. I've noticed a couple of things however. It seems to run more smoothly in some display modes than in others. Might this have something to do with the difference between the NTSC refresh rate and whatever rate my monitor is running at? (I don't know too much about that stuff (yet)). The new behavior seems to make the emulator more sensitive to timing problems when sharing the CPU with another cpu-bound process. Example: I was testing the patch with Super Mario Brothers. After a few minutes, cron started a password-cracking process in the background. Not only did play slow down (as with the old behavior), but every few seconds the graphics would glitch. It looked like it started to redraw the framebuffer, but instead of drawing it at the top of the screen it started in the middle. Kind of hard to describe. :-/ Other than that, it looks good. |
From: Jason D. S. <jd...@us...> - 2004-01-20 17:15:20
|
Ryan Jackson wrote: > Definately! Things look a lot smoother now. I've noticed a couple of > things however. It seems to run more smoothly in some display modes > than in others. Might this have something to do with the difference > between the NTSC refresh rate and whatever rate my monitor is running > at? (I don't know too much about that stuff (yet)). I doubt it. Even if the monitor only updated every other frame you shouldn't notice the difference. > The new behavior seems to make the emulator more sensitive to timing > problems when sharing the CPU with another cpu-bound process. Example: I > was testing the patch with Super Mario Brothers. After a few minutes, > cron started a password-cracking process in the background. Not only > did play slow down (as with the old behavior), but every few seconds the > graphics would glitch. It looked like it started to redraw the > framebuffer, but instead of drawing it at the top of the screen it > started in the middle. Kind of hard to describe. :-/ This is probably because it always sleeps, instead of only sleeping when things get behind. This provides better real-time behavior but makes it more likely that the game can't keep up with real-time. jason |
From: Mike M. <che...@ya...> - 2004-01-20 16:22:57
Attachments:
tuxnes-timeing.diff
|
Yes you are correct, how ever tuxnes takes care of counting ticks in the ASM. Every time we draw a frame it's been 1/60 of a second nes time, so we just need to make the real computer emulate that. In most video games timing will be constant, this way we don't get into complex acceleration equations and such. Too take care of the time we spend when were not sleeping we put the gettime as close as posible to where we sleep. Also I don't normally keep track of total time. I don't know how different the 2 methods are, but I know my way doesn't get overflowed. What I do is reset my tick ctr to 0 every time I sleep, I use the current time to populate basetime(Renamed to lasttime). See my patch for an example that includes a hybrid method. I think it would be safe to remove the "if ( frame > 1800 )", I'd like to here your comments. --- digression --- Yes you are correct, how ever video games use polling. It's not clear what to do with a move once the frame(round) is over, so processing(scoring) of that move MUST wait for the next round. We could take the input and differ scoring, but this would only make the usleep for this round a bit less. It's ok to ignore the input until it's round is being scored. Also the nes uses polling, so we poll when it asks us too. It would be cool to make this script able for things like up-up-down-down... Think mric type nes scripting :) I've attached what I committed it's should hit the backup CVS server in 2 days. mike --- Jason Dorje Short <jd...@us...> wrote: > Mike Mestnik wrote: > > I was chasing a simular problem, but I coulden't get any thing to work. I don't think it's > > correct to cahnge the usleep, as it's based on the NTSC standared. I.E. 16666 = 1 frame and > if > > were n frames ahead 16666 * ( n - 1 ) is how long we wait. > > You don't want to usleep for a fixed amount of time, or you'll get > *behind*. For instance if you sleep for 10 useconds and then do some > calculations that take 5 useconds, your tick length is actually 5 > useconds instead of 10 useconds as you wanted it to be. (Just using 10 > as an example.) > > Instead you want to do your 5 usecond calculations then sleep for just > the remaining 5 useconds. > > The easiest solution is to track the time of each tick. Use a timeval > struct to tell when the next "tick" should occur. Then before sleeping > figure out how long is left between now and then, and sleep for that long. > > Something like: > > struct timeval next, now; > int usec; > > /* This is the only time we call gettimeofday on 'next'. After > * this we just increment it. */ > gettimeofday(&next, NULL); > > while (1) { > next.usec += TICK_TIME; > if (next.usec >= 1000000) { > next.usec -= 1000000; > next.sec++; > } > > do_something(); > > gettimeofday(&now, NULL); > > usec = 1000000 * (next.sec - now.sec) + (next.usec - now.usec); > if (usec > 0) usleep(usec); > } > > In short, something like the attached patch should work. I haven't > tested it, though. > > > --- digression --- > > There are also external events that generally need to be handled. You > generally shouldn't poll for these (however this is NES emulation so > it's probably okay to be inefficient). > > I've generally written network code where you want to call select() > while having a "tick" in place as well. This works great since select > just takes the timeval struct as an argument. > > In GUI code you want to either get interrupts or pass the waiting off to > a GUI function that can handle the interrupts directly. My experience > is in GTK where you call a function to set a timer, then pass control > back to GTK. While GTK has control it can do updates (like redrawing > windows), handle events (if a key is pressed GTK will call your > program's handler for that key), or handle the tick when the time comes > (GTK will call your program's handler for that tick). SDL has something > similar, although it's generally implemented with polling anyway. > > jason > __________________________________ Do you Yahoo!? Yahoo! Hotjobs: Enter the "Signing Bonus" Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus |
From: Jason D. S. <jd...@us...> - 2004-01-20 17:13:32
|
Mike Mestnik wrote: > Yes you are correct, how ever tuxnes takes care of counting ticks in the ASM. Every time we draw > a frame it's been 1/60 of a second nes time, so we just need to make the real computer emulate > that. In most video games timing will be constant, this way we don't get into complex > acceleration equations and such. Too take care of the time we spend when were not sleeping we put > the gettime as close as posible to where we sleep. > > Also I don't normally keep track of total time. I don't know how different the 2 methods are, but > I know my way doesn't get overflowed. What I do is reset my tick ctr to 0 every time I sleep, I > use the current time to populate basetime(Renamed to lasttime). See my patch for an example that > includes a hybrid method. I think it would be safe to remove the "if ( frame > 1800 )", I'd like > to here your comments. > > --- digression --- > > Yes you are correct, how ever video games use polling. It's not clear what to do with a move once > the frame(round) is over, so processing(scoring) of that move MUST wait for the next round. We > could take the input and differ scoring, but this would only make the usleep for this round a bit > less. It's ok to ignore the input until it's round is being scored. > > Also the nes uses polling, so we poll when it asks us too. It would be cool to make this script > able for things like up-up-down-down... Think mric type nes scripting :) > > I've attached what I committed it's should hit the backup CVS server in 2 days. > + if (usec > 0) { > + if ( frame > 1800 ) /* Every 30 seconds */ > + { > + frame = 0; > + renderer_data.basetime.tv_sec = now.tv_sec; > + renderer_data.basetime.tv_usec = now.tv_usec; > + } > + usleep(usec); I think this update needs to come *after* the usleep. if (frame > 1800) { frame = 0; renderer_data.basetime.tv_sec = now.tv_sec; renderer_data.basetime.tv_usec = now.tv_usec + usec. } The time "now" is not significant. The correct time is the time we're usleeping to, which is the time of the start of the current frame (frame 0). Otherwise it'll consistently be off by 1/100 of a second every 30 seconds :-). The next step is probably making it possible to change doublespeed/halfspeed while the game is running. This shouldn't be too hard: when the values are changed reset the frame to 0 and start counting anew. jason |
From: Mike M. <che...@ya...> - 2004-01-21 00:32:42
|
--- Jason Dorje Short <jd...@us...> wrote: > I think this update needs to come *after* the usleep. > > if (frame > 1800) { > frame = 0; > renderer_data.basetime.tv_sec = now.tv_sec; > renderer_data.basetime.tv_usec = now.tv_usec + usec. > } > > The time "now" is not significant. The correct time is the time we're > usleeping to, which is the time of the start of the current frame (frame 0). > Ohh, so that's what thay where doing with the other gettime. I think what you have here is ok. I'l commit this somtime, I wana think about it some more. > Otherwise it'll consistently be off by 1/100 of a second every 30 > seconds :-). > > The next step is probably making it possible to change > doublespeed/halfspeed while the game is running. This shouldn't be too > hard: when the values are changed reset the frame to 0 and start > counting anew. > I forget where you can trap keypresses, there is a select statement some-where. Reserve a key for saving state, I started a branch for it and it's quite close to being testable. Things I'm looking fore are docs on nesticle.sta and that other nes file format. The docs I have on sta are not fully complete and I would like to include a copy of the rom in the image(for game-genie). There is some open nes format but the docs just baffeld me. it seamed to be packet based but no real docs just blerb ware. > jason > __________________________________ Do you Yahoo!? Yahoo! Hotjobs: Enter the "Signing Bonus" Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus |
From: Jason D. S. <jd...@us...> - 2004-01-21 04:27:37
|
Mike Mestnik wrote: > I forget where you can trap keypresses, there is a select statement some-where. Reserve a key for > saving state, I started a branch for it and it's quite close to being testable. Looks like there's already code for this. There's a switch in controller.c. The keypad values change speed (for instance keypad 6 sets 6x speed). They also set desync to 1 and renderer_data.pause_display to 0 (no idea what this means). > Things I'm looking fore are docs on nesticle.sta and that other nes file format. The docs I have > on sta are not fully complete and I would like to include a copy of the rom in the image(for > game-genie). There is some open nes format but the docs just baffeld me. it seamed to be packet > based but no real docs just blerb ware. Several years ago a tuxnes developer (Mike Melanson?) sent me a spec for the common-nes-save-file-format. I doubt that I could find it now, though. At the same time he told me that the nesticle format should be ignored and only the common format implemented. jason |
From: Mike M. <che...@ya...> - 2004-01-21 16:22:57
|
The desync variable should be renamed to framesbehind. When it's more than one we should not call gettime or do the usleep. We should framesbehind-- every frame and set it acordingly after the gettime and before the usleep(Dose not get called when were behind). As for the last time patch it stands as is. The measurement of 1/60 a second applies to everything we do, including the usleep. The fix needed is to redo the ordering. Putting the usleep after we draw the frame before we do the scoring is the answer. It's true we can't find ought how log to wait at that time but we can guess based on how long the last frame took. The loop itself doesn't really have a start or end(it's a loop) this concept is only created by the line numbers and should be ignored. This is the best order IMHO: Scoring(running the emu) before Rendering(Video&Sound) before Gettime&Calculation before Sleeping before Drawing&Playing. Drawing the frame and then calling swapbuffer(if available) after the usleep is a good idea but it's not needed we can render right to the screen. This would mean that any given frame is displayed for exactly 1/60 a second. The draw back is that every frame would be one frame behind the input. This is the case now but it's only part a frame. The problem with nes emulation is that input can be handled mid frame. I don't think we can change the frame after the vsync has ended. --- Jason Dorje Short <jd...@us...> wrote: > Mike Mestnik wrote: > > > I forget where you can trap keypresses, there is a select statement some-where. Reserve a key > for > > saving state, I started a branch for it and it's quite close to being testable. > > Looks like there's already code for this. There's a switch in > controller.c. The keypad values change speed (for instance keypad 6 > sets 6x speed). They also set desync to 1 and > renderer_data.pause_display to 0 (no idea what this means). > I was thinking about putting this code in another process, a fork. Then emulate the nes controller, I have the frequency some where. This would get us away from polling and allow us to do arbitrary input stuff(A bleeding flipper and a menu :). We can use shared memory for the nes registers and a command pipe/socket for every thing else. This other process would also draw the menus and other OSDs. > > Things I'm looking fore are docs on nesticle.sta and that other nes file format. The docs I > have > > on sta are not fully complete and I would like to include a copy of the rom in the image(for > > game-genie). There is some open nes format but the docs just baffeld me. it seamed to be > packet > > based but no real docs just blerb ware. > > Several years ago a tuxnes developer (Mike Melanson?) sent me a spec for > the common-nes-save-file-format. I doubt that I could find it now, > though. At the same time he told me that the nesticle format should be > ignored and only the common format implemented. > A web search didn't turn anything up, http://tuxnes.sourceforge.net/features.php talks about STA and SNSS. I think SNSS will be vary difficult for me to understand. > jason __________________________________ Do you Yahoo!? Yahoo! Hotjobs: Enter the "Signing Bonus" Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus |
From: Jason D. S. <jd...@us...> - 2004-01-21 04:38:06
|
I'd also like to point out that the desync variable is never actually used. It is set in lots and lots of places, but never accessed. What is it supposed to do??? jason |
From: Ryan J. <pro...@ya...> - 2004-01-19 20:11:57
|
Changing the usleep() delay doesn't sound right to me either, but it's the only thing I've found that works. Which gettimeofday() call did you remove: the one in set_timeframe() or set_frameskip()? I tried changing set_timeframe(), but all that happened was the emu ran way too fast. The scrolling was smooth though. :-) What exactly was the problem you were chasing? |
From: Jason D. S. <jd...@us...> - 2004-01-19 20:52:57
|
Ryan Jackson wrote: > Changing the usleep() delay doesn't sound right to me either, but it's > the only thing I've found that works. > > Which gettimeofday() call did you remove: the one in set_timeframe() or > set_frameskip()? I tried changing set_timeframe(), but all that > happened was the emu ran way too fast. The scrolling was smooth though. > :-) What exactly was the problem you were chasing? The problem is that resynchronize() is only accurate to within 1 frame; i.e., 1/60 of a second. Under my patch it should be accurate to within 1 microsecond (1/1000000 of a second). The patch removed both set_frameskip and set_timeframe. The timeframe variable is removed entirely. All we track is the current frame, and from this we can determine what time we should be at. So the usleep sleeps until this time when resynchronize() is called. resynchronize also sets frameskip (if we're more than 1 frame behind) and desync (if we're more than 20 frames behind). jason |
From: Mike M. <che...@ya...> - 2004-01-20 16:34:59
|
--- Ryan Jackson <pro...@ya...> wrote: > Changing the usleep() delay doesn't sound right to me either, but it's > the only thing I've found that works. > > Which gettimeofday() call did you remove: the one in set_timeframe() or > set_frameskip()? I tried changing set_timeframe(), but all that > happened was the emu ran way too fast. The scrolling was smooth though. > :-) What exactly was the problem you were chasing? > It looked like frameskip was getting set and never reset. Ruened my CastelVenia 2 games, I had to reset. __________________________________ Do you Yahoo!? Yahoo! Hotjobs: Enter the "Signing Bonus" Sweepstakes http://hotjobs.sweepstakes.yahoo.com/signingbonus |