PAL/NTSC AND CONVERSIONS One of the problems us programmers are faced with is the multitude of formats that are available. For the PC, heaven forbid when drivers had to be written for each different hardware peripheral. But with Windows, this process is can be sacrificed. Unfortunately, console users will always get two main differing formats - PAL and NTSC. In this document, I will attempt to describe the differing formats, and give suggestions and how to ease conversion between them. Any suggestions or criticisms on this document welcome. James Chow aka jc 6 June 1998 james@chowfam.demon.co.uk --------------------------------------------------------------- DISPLAY OVERVIEW ---------------- In displaying a screen, the beam generating the picture in the television travels from the top left to the bottom right in horizontal lines. (top left) ---------------> ---------------> --------------->(bottom right, now returns to top left) And this occurs at periodic intervals called the vertical refresh rate. The difference between PAL and NTSC is the vertical refresh rate and the number of horizontal lines each format has. NTSC ---- In NTSC, the vertical refresh occurs 60 times a second. And its screen holds 262 horizontal lines. One thing to point out at this particular junction is that the vertical resolution of your game is totally independent to the number of lines the beam has to trace. Say your game was 480 lines in vertical resolution, the television beam will still travel 262 lines. Also, if you draw 262 lines to screen, you will not see all of them, since some lines are drawn *outside* the viewing area. Setting up your game to run in NTSC is simplicity in itself. Just do, SetVideoMode(MODE_NTSC); before anything else, and this sets up the libraries to run in this mode. By default, the libraries are in NTSC mode anyway, but calling this to make sure is a good idea. PAL --- In PAL, the vertical refresh rate occurs 50 times a second. But this is compensated for by an increased vertical resolution of 312 horizontal lines. Again this figure is independent to the vertical resolution of your game, since a number of these are drawn outside the boundaries of your television. To run in PAL mode, we do SetVideoMode(MODE_PAL); //GsInitGraph(..); GsDISPENV.screen.y = 20; GsDISPENV.screen.h = 256; The reason why GsDISPENV has to be altered is because the libraries use the NTSC display environment by default. Even by setting the video mode to be PAL does not actually alter the display environment, and so only 240 lines can be seen even though 256 lines are drawn. Conversions ----------- This is the real pain in the ass to do well. The difficultly in doing good conversion is ("surprise, surprise") the difference in the refresh rate, and the difference in the vertical resolution. In NTSC the aspect ratio is 4:3 whereas in PAL the aspect ratio is 5:4. Yuck!! Yes, the most simplest way to overcome this problem is to #define the screen width and screen height into macros. And setting the video mode as appropriate, we can simply recompile the code, and voila! NTSC and PAL binaries. THIS IS THE WORST WAY OF DOING A CONVERSION!! DO NOT EVEN THINK ABOUT IT!! If you're wondering why, the problem comes from squashing from 240 to 256 (if from NTSC to PAL). This gives those ugly black borders, for us PAL people. OK, so even good games undertake this malpractice, I feel that the same experience should be given to the consumer, irrespective of difficulties. And those who can achieve this will obviously gain an advantage over competitors. I think the way to about this is to apply a scaling factor to everywhere where the vertical resolution is applicable - vertical positioning of primitives, vertical scaling on sprites, and so on. So if we were working in NTSC in 240 y-res, and wanted to convert to PAL in 256 y-res, (example) sprite.scaley = 4096; //for NTSC becomes sprite.scaley = 4096*256/240; //for PAL And for PAL to NTSC, this goes from (example) sprite.scaley = 4096; //for PAL becomes sprite.scaley = 4096*240/256; //for NTSC This in general becomes sprite.scaley = 4096*SCREEN_HEIGHT/WORKING_HEIGHT; WORKING_HEIGHT is the height in which the original y placement was worked out, and SCREEN_HEIGHT is dependent on whether the mode is PAL or NTSC. This obviously means more processing, but it takes fair amount of these scaling factors (00's) before a single hsync passes. (A hysnc is the time taken for the beam to travel a single horizontal line.) The refresh rate is a slightly different problem. Since PAL operates at 50Hz and NTSC at 60Hz, we will always get screen updates running at those respective rates. The problem is the actual timing of the movement of objects in the game. We programmers are a real lazy bunch, and we just increment the location of objects *on a per screen* basis. This is where the difference in speed between PAL and NTSC modes occur. Since PAL runs at 50Hz, and NTSC at 60Hz, PAL therefore runs at 5/6ths (83.33%) of the same NTSC version, a 16.67% reduction in speed. (example) Moving an object 5 units per screen, in one second moves NTSC: 60*5 = 300 units PAL: 50*5 = 250 units Again this is easy to solve, (if only us programmers would just do it this way). By updating the movement of objects proportionately to the refresh rate (or time). To move a piece 300 units in 1 second, NTSC: 300/60 = 5 units per frame PAL: 300/50 = 6 units per frame To make this an easy task to do, we do #define REFRATE 60 //or 50 if PAL sprite.x += 300/REFRATE; There is one final less obvious problem regarding the updating of screens. We must finish drawing to the off screen buffer within the time for the next swap. If the off screen buffer is not ready to swap, the frame is delayed until the beam reaches the vertical retrace again. To make it smooth, it is best not to take too long drawing the frame. In PAL we have to be ready to swap every 1/50th second, and in NTSC every 1/60th second. There is no workarounds for this, but we must simply finish calculations and all within the time. Personally, I work to the most restrictive specification, and then the conversion to the other mode will be at least equivalent. I work in PAL dimensions, 1.25 aspect ratio. And ensure that the off screen is ready to be refreshed very much within 1/50th second. It must be well inside this limit, so that when scaling factors are applied, we can reach 1/50th second refresh limit, without any problem. What is of utmost importance, is that both formats must be remembered during the development of the game. It is very easy to slip in 240 instead of the SCREEN_HEIGHT macro, and to work on a per screen basis. But by just thinking of the other format, multi-format code comes easy. Some Macro Conversion Code -------------------------- #define PALVER //comment this out for NTSC #ifdef PALVER #define REFRATE 50 #define SCRN_HEIGHT 256 #else #define REFRATE 60 #define SCRN_HEIGHT 240 #endif void main(void) { #ifdef PALVER SetVideoMode(MODE_PAL); #else SetVideoMode(MODE_NTSC); #endif //call GsInitGraph(..) here #ifdef PALVER GsDISPENV.screen.y = 20; GsDISPENF.screen.h = 256; #endif }