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
}