Amiga example which displays a rotating square on a PAL screen.
To give you a better impression, the demo can be seen on youtube:
Two options exist. The project can be either
- crosscompiled with makefile, GCC and vasm
- or install my amiga build
docker container and run
docker-run.sh
The planar to chunky buffer conversion is perfomed via PlanarToChunkyAsm()
written
by Morten Eriksen. The chunky to planar conversion can be controlled at compile
time by #define NATIVE_CONVERTER
:
- If defined, AmigaOS native function
WritePixelArray8()
is used. - If not defined, the converter invokes
ChunkyToPlanarAsm()
.
Important: WritePixelArray8()
seems to have problems with padding
bytes if buffer width % 8 != 0
. I assume there is a mistake on my
side, so use with caution ;)
This implemetation starts with a series of boiler plate code statements:
- Set an empty mouse pointer via
SetPointer()
to hide curser from screen - Allocate a temporary bitmap which can be later used by
WritePixelArray8()
- We use double buffering, therefore we create two Screens (including the corresponding BitMaps)
- Allocate two chunky buffer in fast memory (
MEMF_FAST
parameter can be ommitted but I wanted to make sure it really uses the memory of my accelerator card). - Allocate memory for color table
- Create
rectBitmap
which will contain the square - Paint square into
rectBitmap
, transform to chunky format and save result insrcBuffer
Afterwards, this example executes a loop which
- Rotates the square by 10 degrees
- Shows the result on screen
- Checks whether mouse key was pressed. If yes: Terminate
In case of program termination, the previously allocated buffers are freed and the mouse curser restored.
The rotation is perfomed in rotate()
with the following parameters:
- Source buffer
srcBuffer
which contains the original non-rotated square - Destination buffer
destBuffer
- Rotation angle in in degrees
- Buffer width and height
The rotation algorithm iterates through each y and x pixel of the destination buffer. Each pixel is multiplied with a rotation matrix:
src_x = x*cos(360 - alpha) - y*sin(360 - alpha)
src_y = x*sin(360 - alpha) + y*cos(360 - alpha)
The resulting coordinates are transfomed into array indices and used to write the color values
of srcBuffer
into destBuffer
:
dest_index = x + y * rd->width;
src_index = (src_x + (rd->width / 2)) +
((src_y + (rd->height / 2)) * rd->width);
if (src_index < 0 || src_index >= (rd->height * rd->width))
{
continue;
}
(rd->dest)[dest_index] = (rd->src)[src_index];
The first implementation was really slow, maybe one frame per 5 seconds on my A1200 with 40Mhz 68030 CPU. Therefore, I added the following optimizations:
- I moved some multiplications from
rotatePixel()
into the y loop. This way, the calculations are only performed once per row and not for each pixel. - The scripts lookup_cos.py and lookup_sin.py precalculate the values of the trigonometric functions and create lookup tables.
- I removed the float calculations and switched to fix point with a set of basic macros I found here.