Graphic Animation

In the good old times, when studying at the University of Trieste, I particularly enjoyed Rational Mechanics, a required class for any EE Master back then, presented by professor Enzo Tonti. One of the things that were always making his lectures a pleasure (and a challenge) was his constant reference to, and practical use of, personal computers to illustrate visually the concept at hand.

Mind those were the early days of the Apple II, the Commodore C64, the Sinclair Spectrum and for the few lucky (and rich) ones among us the first IBM XT personal computers. The graphic capabilities of those personal computers were primitive to say the least. In fact, a single PIC24F128GA010 has today more program memory than any of those personal computers and the resolution of the video output, using the AV16 board we developed in the book (without any hardware assistance), is actually pretty close. Yet prof. Tonti used to teach us how to develop effective demos using little more than a few lines of BASIC or, I should say, of the “soup” of BASIC dialects that were popular at the time… (Actually prof. Tonti developed a brilliant scheme to identify a sort of minimum common denominator among all those disparate systems and Basic dialects that he called Inter-Basic if I recall correctly… there must be a web site somewhere where all this is documented)…

We simulated graphically the motion of planets around a sun, the complex motion of pendulums of various kinds, we animated objects in 2D and 3D! Key to all those graphic exercises was the ability to alternate fast images on the display to obtain the illusion of motion….

Every program would consist of a simple simulation loop composed of the following steps:

  1. Initialize all the variables (position, speed) for each object
  2. Clear the screen
  3. Draw the “object” ( sometimes just a point)
  4. Consider all forces at play (accelerations)
  5. Compute the new speed and position
  6. Repeat from 2

Each pass in the loop from 2 to 6 approximated in the simulation an infinitesimal amount of time “dt”. In step 4, is where the “laws of motion” were integrated by multiplying the accelerations by dt to obtain the new speeds (linear and angular) and the speeds were integrated by multiplying by dt to obtain the new object position in (the given) space.

All fine and dandy except for the fact that the visual effect would be rather “flashy”!

In fact during the time between the clearing of screen (2) and the object been redrawn in the new position (3), the image would sort of disappear or appear partially incomplete. The more complex the object been drawn and the worse the visual effect.

The solution to this basic graphic problem was quite simple, although not always available (in BASIC) on all the personal computers we used back then, it is called “double buffering”.  In practice you want to use two image buffers, at any given point in time only one of the two (containing a finished image) is visible on the screen, while the other one is being worked on, sort of in the backstage.  So the simulation/animation loop can be rewritten as:

  1. Initialize all the variables (position, speed) for each object
  2. Clear the hidden screen
  3. Draw the “object” on the hidden screen ( sometimes just a point)
  4. Swap the screens (making the new image visible)
  5. Consider all forces at play (accelerations)
  6. Compute the new speed and position
  7. Repeat from 2

Step 4 is the only new step in the loop and on some graphic systems it was as easy as changing one pointer (Apple II) while on most others, less flexible, it was necessary to perform a copy operation instead, to transfer the entire contents of the hidden buffer onto the visible screen memory.

In order to perform similar animations with the graphic library we developed for the PIC24 (and the AV16 board) we have to make only a couple of simple changes. First of all we have to allocate two separate buffers capable each of containing the entire image (VMap1, VMap2), then we have to define two pointers, we’ll call them VA and VH:

  • VA will point to the active and visible image buffer.
  • VH will point to the hidden image buffer where we perform the actual drawing.

Modifying the plot() and line() functions  (as well as the putcV() and putsV() for text) to refer to the VH pointer rather than working directly onto the VMap array is easy.

Finally a new function swapV() is required to perform the trivial swap of the two pointers and voila’, we have smooth and fast animation!

Unfortunately, unless you are trying the code on one of the latest PIC24 models with more RAM memory than the 8Kbytes given to the PIC24FJ128GA010, you are going to discover soon that there is no room for two complete buffers.  At least not of the size we used so far in the examples of Chapter 12 (192 x 256). We will have to reduce our pretenses and stick to a reduced resolution, 160×160 for example, so that we can fit both VMap arrays and leave some memory for the main program itself and the stack.

160 x 160 / 8 = 3,200 bytes

3,200 x 2 = 6,400 bytes leaving 1,600 bytes in total for program variables and stack.

Here is the new double buffered graphic library:

graphicDB.c

graphicDB.h

(Note: it includes the latest optimizations offered in the previous posting for maximum efficiency, therefore it will require you to modify slightly the AV16 board)

(to be continued)

This entry was posted in AV16/32, Graphics, Tips and Tricks. Bookmark the permalink.