Going Hi-Res

Often using 320*240 or thereabouts, gives a horribly low definition
to the picture. Such that, it hinders the visual element of the game.
We all like nice graphics and that, so to achieve smoother visuals
high resolution is a must.
In this document, I will give describe how to get into hi resolution.

Any suggestions or criticisms on this document welcome.

James Chow aka jc             22 June 1998
james@chowfam.demon.co.uk
---------------------------------------------------------------


The Display
-----------
In normal resolution the beam traces every line from top to bottom.
However, due to the way a television works it is not possible to go in
a higher resolution than the number of lines it can scan. In NTSC
this is 262 and in PAL this is 312.
Due to smart trickery, we can actually go higher than this. In
interlaced mode, we display all the even scan lines in one frame, and
in the subsequent frame all the odd scan lines. By rapidly changing
between the two frames, we can effectively double the vertical
resolution of the display.
To work in interlaced we must initialise the graphics system by,
      GsInitGraph(SCNW,SCNH,GsOFSGPU|GsINTER,0,0);
where SCNH is 480 or 512 appropriately.

Since in interlaced mode, either even lines or odd lines are used,
the frame buffer is optimised so that the display buffer and the
off-screen buffer can overlap. We therefore set the two display
buffers to overlap in the frame buffer,
      GsDefDispBuff(0,0,0,0);

And that's it! Really? Not quite, read on.

Hi-Res Restrictions
-------------------
One of the problems in working in high resolution is that all
calculations and drawing must be completed in time for the vertical
retrace. There are no if's and but's here, it MUST be done
otherwise the off screen buffer is displayed incomplete.
To ensure that drawing is complete, we can either code it so
that it will finish in time. If we don't know if this can be
achieved, we must abort all the drawing commands at the time
of the vertical retrace. We do this by

    VSync(0);
    ResetGraph(1);   //erase drawing commands
    GsSwapDispBuff();

Another thing, I find when working in hi-res is the distinct
lack of video memory. Say working in 640*512 PAL, leaves only
384*512 free for placing sprites. This is usually a very tight
fit, which may result in having to scale down the original sprites.
By scaling down the sprites, and then having to scale them back
up again to the intended size for display loses the smoothness
strived for in converting to hi-res. Augh!!

Depending on the type of game being written, it may be better
to use slight variations to the resolution. Using the concept
of a scroller shoot-em-up, we can differentiate between the
two. For a vertical scroller, the height definition is more
important than the width and so working in hi-res vertically
is more desirable. Say, 320*480.But this means having to keep
to the vertical retrace conditions.
On the other hand, for a horizontal scroller the horizontal
definition is more important. So using, say 512*240 may be better.

PAL Problems
------------
Unfortunately, there is an error in the libraries, such that
it makes it impossible to display the maximum 512 lines.
Basically the clipping range lies at 511, so the last line is not
updated correctly. This gives rise to a whole host of problems.
Obviously, the bottom line is not cleared during each frame.
This means, when a sprite runs over the bottom line, a trace
is left behind.
Also, primitives exceeding vertical height of 512 are ignored,
and this includes the very useful, GsSortClear().

One possible workaround to this problem is to work to 512 lines.
And hide the bottom 2 lines, (we cannot hide one, since we are
in interlaced mode). Also, manually clearing the background,
either by drawing a suitably sized filled box, or by altering
GsDRAWENV.

Some Code
---------

#define PALVER   //comment this out for NTSC

#ifdef PALVER
  #define SCRN_HEIGHT   512
#else
  #define SCRN_HEIGHT   480
#endif
#define SCRN_WIDTH   640

void main(void) {
  #ifdef PALVER
    SetVideoMode(MODE_PAL);
  #else
    SetVideoMode(MODE_NTSC);
  #endif

  GsInitGraph(SCRN_WIDTH,SCRN_HEIGHT,GsOFSGPU|GsINTER,0,0);

  #ifdef PALVER
    GsDISPENV.screen.y = 20;
    GsDISPENF.screen.h = 255; //not 256! bug: can't use bottom line!
    GsDRAWENV.isbg = 1;
    GsDRAWENV.r0 = 0;         //clear the background by GsDRAWENV
    GsDRAWENV.g0 = 0;
    GsDRAWENV.b0 = 0;
  #endif
  GsDefDispBuff(0,0,0,0);

  while(1) {
    //some game update code
    VSync(0);
    ResetGraph(1);   //remove if can finish drawing in time
    GsSwapDispBuff();
    //GsDrawOt();
  }
}