|return to ChibiAkumas.com||Choose a Color Scheme:||Dark|
| Lesson P1 - Bitmap Functions on
The x68000 has a built in dedicated graphics card, it's memory is accessed through the normal addressable range, but there are some quirks!
In this lesson we'll learn how to set up the graphics screen, print text from a 1bpp font, and draw a bitmap to the screen!
|High Resolution||Low Resolution|
|E80000||$89||$5B||$5B||$2B||$4B||$4B||$25||R00 Horizontal total|
|E80002||$0E||$09||$09||$04||$03||$03||$01||R01 Horizontal synchronization end position timing|
|E80004||$1C||$11||$11||$06||$04||$05||$00||R02 Horizontal display start position|
|E80006||$7C||$51||$51||$26||$45||$45||$20||R03 Horizontal display end position|
|E80008||$237||$237||$237||$237||$103||$103||$103||R04 Vertical total|
|E8000A||$05||$05||$05||$05||$02||$02||$02||R05 Vertical synchronization end position timing|
|E8000C||$28||$28||$28||$28||$10||$10||$10||R06 Vertical display start position|
|E8000E||$228||$228||$228||$228||$100||$100||$100||R07 Vertical display end position|
|E80010||$1B||$1B||$1B||$1B||$44||$44||$24||R08 External synchronization horizontal adjust: Horizontal position tuning|
|E80028||$05||$01||$00||R20 Memory mode/Display mode control|
|E80400||$00||$00||$00||R0 (Screen mode initialization) - Detail|
|E80500||$3E4||$3E4||$3E4||R1 (Priority control) - Priority|
|E80600||$81||$81||$81||R2 (Special priority/screen display) - Screen On|
|EB080A||$FF||$FF||$FF||$FF||$FF||$25||Sprite H Total|
|EB080C||$15||$15||$0A||$09||$09||$04||Sprite H Disp|
|EB080E||$28||$28||$28||$10||$10||$10||Sprite V Disp|
|EB0810||$15||$11||$10||$05||$01||$00||Sprite Res %---FVVHH|
|We're going to
define a 'screenInit' routine which will turn on the graphics screen -
we can choose the resolution we want by defining a symbol, such as Res256x256
These Tutorials are using a 16 color mode (as it's most common on retro systems)
We need to set up the CRT parameters which will define how the screen image is formed - we also need to define the registers which will configure the screen layout.
Note: we're not doing anything with the sprite registers at this time - at the time of writing, hardware sprites are not used in these tutorials, though theyy may be added later!
if you want more info on the registers, please see the GamesX website, or the (Japanese) X68000 technical data book
|The X68000 is capable of multiple
color depths and multiple layers of paralax,
In these tutorials we're only going to use one 16 color layer - the reason for this is that we're going to do the same on a wide variety of 68000 systems (and even the same tasks on z80 and 6502 systems) and the vast majority of these systems support 16 color, but few support 256 colors.
|The X68000 screen
is memory maps to the hardware, but it's slightly odd compared to other
Each screen pixel uses two bytes of memory WHATEVER the screen mode! - so whether you're using 4bpp or 8bpp, you're still going to use
|We're going to use
register to write data to the screen - we'll use a 'GetScreenPos'
command to convert an X,Y pos (in D1,D2)
We're using Graphics Screen 0 - which starts at $C00000...
Each X pixel takes 2 bytes - so we do a ROL to shift X left 1 bit
Each Y line is 1024 bytes, so we do 8+2 ROL's to shift Y left 10 bits... we can't do ROL #10, the command doesn't support it
|We have a GetNextLine command to move down a line as well...|
|We can show a
bitmap sprite to the screen, buy using the GetScreenPos command to set
the correct memory position in A6
We're going to read in a sprite in 'Packed format' where both nibbles of the byte is used - we'll need to split these up and write them in separate words to the screen memory
We need to use GetNextLine to move down after each complete line.
|VSync on the X68000
via the MFP (MC68901)... we can test bit 4 to see if the screen is in
Vsync... by waiting for Vsync to start and end, we can make sure a new
vsync starts before we continue processing...
This was used in the Grime 68000 game
|This Vsync routine was used in Grime 68000 to slow down the game, but it's not perfect, on a 100mhz x68 it's much faster than a 1st gen machine... but this is the best the author has managed to do so far!|
routine will show an Ascii character in D0 to the screen...
Essentially we're using the same code as above, but now we're using Cursor_X and Cursor_Y as 'character position' for calculating the screen postion
When it comes to actually plotting to the screen, we're popping of a bit of the font lines, and moving it to 'color 15' of the byte, before drawing it to the screen.
Once we've drawn the character to the screen, we increase the X position - and see if we've reached the width of the screen, if we have then we run the NewLine command to wrap to the next line.
|You'll need to define Cursor_X and Cursor_Y in ram somewhere... also not there's some simple LOCATE and CLS commands not shown here, download the sources.z7 if you want to see them!|
| Lesson P2 - Bitmap Functions on
the Atari ST
The Atari ST has a ram based screen - we can just allocate some memory, and write data to it to get it on screen...
The layout is a bit odd - it's split into bitplaines in 16 pixel Words... lets see what that means!
|Lets take a look at how bitmap data is stored on the
The screen is 16 color - which means we need 4 bits for each color...
These colors are stored in 'Bitplanes' - this means each byte defines one of the color bits for 8 pixels.
On the Atari ST pixel data is stored in words... 16 pixels worth of data for a single bitpalne are stored in a Word... the next word will be the next bitplane for the same 16 pixels... and so on for all 3 bitplanes...
After all 4 bitplanes for the first 16 pixels, the next 16 pixels will start...
The screen is 320 pixels wide, so each line is 160 bytes across... and Line 1 is 160 bytes after Line 0 in the memory.
|FF8200||RW||-------- HHHHHHHH||Video Base H||Need 32256 bytes per screen|
|FF8202||EW||-------- MMMMMMMM||Video Base M||Can’t specify L byte|
|FF8240||RW||-----RRR -GGG-BBB||Palette Color 0|
|FF8242||RW||-----RRR -GGG-BBB||Palette Color 1|
|FF8244||RW||-----RRR -GGG-BBB||Palette Color 2|
|FF8246||RW||-----RRR -GGG-BBB||Palette Color 3|
|FF8248||RW||-----RRR -GGG-BBB||Palette Color 4|
|FF824A||RW||-----RRR -GGG-BBB||Palette Color 5|
|FF824C||RW||-----RRR -GGG-BBB||Palette Color 6|
|FF824E||RW||-----RRR -GGG-BBB||Palette Color 7|
|FF8250||RW||-----RRR -GGG-BBB||Palette Color 8|
|FF8252||RW||-----RRR -GGG-BBB||Palette Color 9|
|FF8254||RW||-----RRR -GGG-BBB||Palette Color 10|
|FF8256||RW||-----RRR -GGG-BBB||Palette Color 11|
|FF8258||RW||-----RRR -GGG-BBB||Palette Color 12|
|FF825A||RW||-----RRR -GGG-BBB||Palette Color 13|
|FF825C||RW||-----RRR -GGG-BBB||Palette Color 14|
|FF825E||RW||-----RRR -GGG-BBB||Palette Color 15|
|We need to define some ram for the screen...
we're going to define a 'BSS' section in our code...
Data in this section does not exist in the compiled file... but any data areas in it will be allocated by the operating system ... they will ALLWAYS be initialized to ZERO, so we can only use DS to define areas, not DC
Because we need the bottom byte of the screen start to zero, we're going to allocate 256 bytes more than we need.
|We'll start by changing the screen resolution by
writing $00 to $FF8260
Now we need to use the address of the ram we defined in the BSS section... however we need to zero align it - as we can't set the Low byte of the screen address
Lets assume the screen_mem symbol has the address $00123456...
Our aligned screen will be $00123500... we'll store this in 'ScreenBase' ... but when we store this into $FF8200 - we need the two bytes to be in the low bytes of the words... so we shift it... converting $00120035
Finally, we'll define some basic colors to start us off
|We're going to define our GetScreenPos function we'll
take an Xpos (in bytes) in D1, and a Ypos (in lines) in D2
We'll have to calculate an offset to our screen base... as the 4 bitplanes of16 pixels (2x4 bytes) are grouped together, for every 16 pixels, we move 8 byte... we do this by ignoring the bottom bit of the Xpos, and doing 2 bit shifts
but we need to move along one, to the middle of the word if the selected screen byte is odd... we do this by adding the bottom bit of the XPos
Each line of the screen has 160 bytes... so we multiply the Ypos by 160, and add this to the screen position...
This gives us the resulting position to write our byte data to
|If we want to move down a line, we can just add 160 to our current position to do it.|
|We may need to wait for VBlank to delay our games and
make them run at even speed...
We can use function $25 of Trap 14 (Xbios) to wait for the vblank.
|Alternatively we can use the Vblank counter at address $462 - this is a counter that's updated by the firmware every time vblank occurs.|
|Ideally, we'd rather go direct to the hardware and detect VBLANK rather than using the firmware, but the author of these tutorials is too stupid to figure it out!... if you know how, please give him a clue - and tell him how it works!|
|We're going to
define our bitmap with all 4 bitplanes in concecutive bytes (this is
the same format we'll use for the amiga)
This means we'll have to write all the bytes to the 4 bitplanes - and we'll have to move in an odd pattern:
We'll write 4 bytes (offset to point to the bitplane) - move 1 byte , then write another 4 bytes (also offset to point to the bitplane),
Finally we'll move another 7 bytes... this will move to the start of the next word... and we'll repeat the procedure again!
could use Atari ST native format, but there are advantages to storing
the data byte aligned, and converting it to word alignment.
The reason we're doing this is it allow us to write to any byte aligned X position - whereas if we used native Atari ST screen foramt we'd have to be word aligned.
| Lesson P3 - using the FIX layer to
draw bitmaps on the NeoGeo
The NeoGeo is not a bitmapped screen - so we can't set pixels in memory ... and unlike other consoles, the NeoGeo's backgrounds are made up of 16x16 Sprites not an 8x8 Tilemap...
However the NeoGeo does have an 8x8 FIX layer - which is deigned for onscreen text and other such stuff - and to get us started, we can use it to do our Chibiko Bitmap!
systems will have 2
types of graphics layer... a 'Tile Map' which is a grid of predefined
'tiles'... these are usually 8x8 in size... on a 16 bit system, usually
multiple layers of tilemaps exist to define parallax...
On top of this we would add sprites to make our player character and other such things...
But the NeoGeo HAS NO TILEMAP!
|So how does the
NeoGeo work with no Tilemap?
Well... sprites on the NeoGeo are 16 pixels wide, and can be up to 512 pixels tall - but they can be combined!... and because the NeoGeo is capable of a whopping 380 tiles, we can combine 20 of them together to 'simulate' a tilemap!... this is how background graphics are drawn on the Neogeo!
On top of this are our 'normal' sprites - enemies, player characters and such...
There is one final layer, the 'Fix Layer'... this is made up of 16 color 8x8 tiles, in a simple grid... it's designed to do onscreen text and the like... but I used it in GrimeZ80 to do all the game graphics... so if your needs are simple, and you want 8x8 block graphics, it can be used for the job...
but don't worry, we'll learn about sprites later
|Grime 68000 used the FIX map for all it's
graphics... but we should have probably used Sprites...
Sprites are 16x16 - but the NeoGeo has Hardware scaling, so we could scale them down to 8x8 - We'll learn all about Sprites in a later lesson!
|The Neogeo screen has a resolution of 320x224, and each
tile is 8x8 - giving an effective screen size of 40x28...
The actual tilemap is 40x32... the top and bottom two lines are not show (Shown in red on the chart to the right)
However, because of the CRT layout - it is likely that the left and rightmost 1 column will not be visible (Shown in orange to the right)... this gives a visible screen of 38x28
The Fix Layer is positioned in VRAM at &7000 (each position contains 1 word / 2 bytes)- each Tile is defined by 16 bits in the following format:
Where P is the Palette number, and T is the Tile number
The fixmap appears at $7000 in Vram... tile data for the Fixmap are in ROM
Each address contains a WORD...
Write a word to $3C0000 to select VRAM Address
Write a word to $3C0002 to Send data to VRAM
Tiles in memory are ordered in COLUMNS... so in memory (X,Y) co-ordinate (0,1) comes after (0,0) ($7000)... and (1,0) comes 32 words ($7020) after (0,0)
For example - to set tile (0,2) to tile 256 in palette 1 (note this is in the "May be offscreen" area, but should appear on an emulator)
Move.W #$7002,d1 ;Address - Tile 2
Move.W #$1100,d0 ;PTTT - Palette and tile
Move.w d1,$3C0000 ;set address in vdp
Move.w d0,$3C0002 ;set tile data in vdp
|Fix Layer tiles are in an odd format!
Each tile is 8x8 at 4bpp ... so 32 bytes per tile...
The two nibbles of each byte represent 2 pixels , but they are BACKWARDS... so the 1st (High) nibble is the 2nd pixel color, and the 2nd nibble (Low) is the 1st pixel color
The bytes are stored in Columns, then rows... and the columns are out of order too! .. Visible pixels ABCDEFGH are stored in Ram in order FEHGBADC
The 8 bytes of each column are in normal top->bottom format... so at least that:s something!
|My AkuSprite editor (used in these tutorials) has support to export images in the correct "FIX" format for the NeoGeo|
|The FIX and SPRITE formats are different on the
NeoGeo which is VERY ANNOYING!
You can use AkuSprite Editor to create valid files - and remember, it's open source, so if it doesn't do the job well enough, you can use the source to make something better!
|We need to define our FIX rom data in the NEOGeo.XML...
we'll split the fix data into 3 files...
NAME specifies the filename
OFFSET specifies the memory position in the 'ROM' of the Neogeo
SIZE is technically the size of the file - but mame doesn't seem to check if it's correct (Warning: it does with sprites!)
CRC / SHA1 - these are hashes of the rom - if they are incorrect MAME will complain
we're defining 3 files
202-s1.s1 - This is the NEOGEO firmware fonts, we'll leave them alone
FONT.FIX - This is the ChibiAkumas font used by these tutorials, you'll need this for the PrintChar routines to work
RawNEO.FIX - this is the bitmap data we're going to use today to show 'Chibiko' onscreen!
|If we want to create a 'proper' rom file, we'll need to calculate the correct Hashes, but it's quicker to skip it, and the game will run, so it's OK for our testing|
|We're going to put
our 'Chibiko' character on the screen, the sprite is 48x48, so it's
made up of 6x6 FIX tiles...
We'll set the correct positions of the fix tilemap to the parts of the bitmap.
|We're going to use
called FillAreaWithTiles... this will take a start XY position, a Width
and Height, and a start Tilenumber... it will fill the entire area with
consecutive tiles Left->Right, Top->bottom
Note... the NeoGeo works the opposite way: Columns first, then Rows
We're allocating tiles 0-255 for our font, so we're using tile 256 for our Chibiko Bitmap
|When we call our
FillAreaWithTiles function, we'll need to convert the X,Y co-ordinate
into a memory
The first 2048 tiles ($800) are used by the firmware - we're also going to use Palette 1 - so we add $1800 to the tile number to get the data we write into VRAM
We then need to calculate the offset in the FIX map for the tile we want to change... the fixmap is organized in Column/Row order (Going down then Across)...
We do this by adding X*32+Y to the start address of the fixmap ($7000)
We shift the Xpos left 5 times with ROL.L #5 - multiplying X by 32...
Because the top 2 lines of the NeoGeo screen are not viewable, we add 2 to the Ypos
To set the Tile, we write the address we want to change to $3C0000.... and the TileNumber/Palette to $3C0002
We repeat the procedure for each of the tiles we want to draw to the screen.
| Lesson P4 - Bitmap Functions on
the Sinclair QL
The QL's graphics are visually very different to the other 16 bits (if you count the QL as 16 bit!!)
It uses a fixed palette, of 8 primaries (RGBCMYWb) in mode 8, or 4 in mode 4 (bRGW)
|The Screen is
memory mapped from $20000-$28000, it
is also possible to have a second page at $28000-30000, but this will
render the OS unusable, as it's fixed variables are in that memory
Lines are in a linear format, with each line 128 bytes below the last... two concecutive bytes make up 4 pixels in 8 color, or 8 pixels in 4 color mode.
There are two possible screen modes, configured by bit 3 of port $18063
setting a 0 give 4 colors at 512x256 with Black,Red,Green and White
setting a 1 give 8 colors at 256x256 with Black, R, G B, C, M, Y and White
There is no palette - the colors are fixed... it is not possible to have 'brightness levels' - colors are on or off.
My AkuSprite Editor can export 4 or 8 color bitmaps, however it does not support Flashing mode.
4 Color mode:
8 Color mode: (F is flashing)
|Flashing only works in 8 color mode -it's a HARDWARE
flash, and does not use th interrupts or firmware.
A flashing bit of 1 will toggle flashing ON or OFF... flashing always starts as OFF at the start of a line
When a Flashing bit 1 is set - all subsequent pixels will flash between their normal defined color and the color of the pixel with the flashing bit set.
F= Flashing bit of 1
Emulators don't bother to emulate FLASHing... QLAY2 doesn't do it, and
Q-Emulator doesn't seem to do it right except in full screen mode...
The latest versions of Zesarux DO seem to do it well though...
That said, Falshing mode is pretty dumb anyway, so you're not missing anything important if your emulator doesn't support it!
|When we want to change screen mode, we just set bit of
$18063 according to the mode we want...
a 1 will set 8 color mode... a 0 will ser 4 color mode!
|When we want to
calculate the memory location of an X,Y position, it's pretty easy.
using an X position in 4/8 pixel blocks, and Y in lines we can use following
Each 8 pixels uses 2 bytes, so we bit shift the X pos in D1 by one bit.
Each line uses 128 bytes, so we bit shift the Y pos in D2 by 7 bits.
Then we add $200000 - the offset to the start ofthe screen.
|When we want to use
this, we just need to copy the bytes from our source (created by
AkuSprite) to the screen,
After each line we use GetNextLine to move down the screen to start drawing the next line...
Because 4 color mode has twice as many pixels per byte, we need to alter our line total in D1 depending on if we're in 4 color mode or not.
|This routine will
show a simple bitmap...
We also have 'PrintChar' routines, these use a 1bpp font, and show letters from a common font (used on all the systems)
Sinclair QL's screen is pretty limited for a 16 bit machine, but
remember... it's an 68008 - which has an 8-bit data bus, so technically
it's and 8 bit machine... this means it's much slower than an Amiga or
similar... and you'll have to optimize yout code more to keep the games
The reduced graphics were probably and unavoidable sacrifice considering the price-point and early release of the machine.
|We can use Vsync to slow down our game... by waiting
for Vsync, we can wait for the next screen redraw
If we want to test for Vsync (the start of screen redraw) we need to use Port $18021... bit 3 will go high (1) when Vsync starts... we need to write a 1 to that same bit at the same port to clear the Vsync event...
Therefore, in effect we can write 255 to port $18021, then read from $18021 until it's nonzero to get the Vsync event.
|$18021 Read||B||M||R||X||F||T||I||G|| B=Baud
M=Microdrive inactive, R=Rtc
Interface interrupt G=Gap
|$18021 Write||R||F||M||X||F||T||I||G||R=tRansmit mask, F=interFace mask, M=gap Mask,X=reset eXternal Interrupt,F=reset Frame vsync, T=reset Transmit interrupt, I=reset IPC Interface interrupt G=reset Gap interrupt|
| Lesson P5 - Bitmap Functions on
The Genesis is a Tile - Sprite based system... this means we can't just plot data to the screen... we need to define our bitmap data as tiles in vram, then set those tiles as visible onscreen...
Lets give it a go!
|We need to initilize our screen, to do this we need to set some VDP settings... these start with $8nvv - where n is the register number and vv is the value for the register... we'll load these from the table VDPSettings|
|We'll be using the
values shown for our tutorials...
you can change the values if you wish, but if you change things like the name table positions, the tutorials will not work correctly unless you also alter the code that draws characters and tiles to the screen
|We're going to set
up a simple palette to get us started...
Basically, each color in the palette has two bytes defining it's RGB value, but we're not going to go into more detail at this stage, as we'll be covering it in more detail later.
|We've now done the basics... so we'll start the screen display, then convert our 2 bit font to tiles in the tile definitions.|
Reg 16 to 01 defines a tilemap of 64x32 - we could define one that's
32x32 or 64x64, but as our visible screen is 40x28 so 64x32 seems a
If you change it, or the memory address of Scroll A, then you're going to have to change the rest of the code in todays example!
|When we want to write data to the VDP, we just write
the data value to address $C00000 (vdp_data).... but first we need to
select the VDP destination address using $C00004 (vdp_ctrl)
We'll need to select addresses from $0000-$C000 to define our tiles and each tile takes 32 bytes.
Unfortunately, because the VDP address select is designed to be backwards compatible with the SMS, the bytes we have to send to select the port are a little odd!... Effectively the top two bits of the address are moved to the bottom two, and the top two bits are set to %01...
you can see some how various sample VDP addresses convert to address select commands in the table to the right.
memory is really confusing... but don't worry, we're going to create a
little function that will do all the work for us!
The reason it's so confusing is the Genesis was designed to be backwards compatible with the Master system... that's why the genesis uses a Z80 for it's sound chip - it can be used as the main CPU for SMS support!
|To simplify sending data to the VDP we'll create a command called 'PrepareVram'
This will calculate the correct address to write to within the VDP
|When we want to define tiles, we'll just copy the tile data into the VDP...
We'll define the start of the tile definitions in A0, the destination in vram in D2, and the bytecount in D1
|When we want to transfer our tile definitions to VRAM, we can just call this 'Define Tiles' command.|
|Of course, you'll need to convert a bitmap into the correct format for the VDP... but you can do this with my AkuSprite editor!
It's free and open source, and you'll find it in the sources.7z
editor supports all the systems covered by these tutorials... and It'll
be extended to cover any systems added in the future.
It's only a basic program, but you can load bitmaps in via the clipboard so you can use a more advanced eitor like Krita to do the hard work
|We've now got our 'Chibiko' bitmap in vram as patterns, but
we need to get it on screen... the bitmap is 48x48 pixels... meaning
it's made up of 6x6 (36) tiles...
To show our bitmap on the screen we need to set the tiles in the positions we want to the correct pattern numbers for our bitmap!
|We're going to define a command called 'FillAreaWithTiles'
We'll pass it a Start XY position, a width and height, and a start tilenumber (256 - the first 128 are used by our font)
The command will calculate and set the tiles to get our bitmap onscreen!
|We've defined our tile map as 64
tiles wide, and 32 tiles tall... each tile definition takes 2 bytes...
this means each row of the tile map is 128 bytes...
Therefore, to calculate our memory address within VRAM, we use the formula $C000+(Y*128)+(X*2)
T=Tille number H=Hflip V=vflip P=palette number
L=Layer (in front of /behind sprites)
|We're going to merge our calculation of the byte position in VRAM and our 'PrepareVram' command to save CPU power,
For each line, we'll calculate the starting address of the line and send the VRAM select command to the VDP
We'll then start writing our tile numbers to VRAM... The VRAM address automatically increments after each write, so we don't need to recalculate until we've completed the whole line, but we do need to increment our tile number in D4
After each line we recalculate the memory position for the row below,
We continue this procedure until the the bitmap is drawn to the screen!
|Of course this is just a simple example... but you can use it to create something better... Take a look at Grime 68000 if you want to see a more advanced example!
We've only looked at Tiles so far, but don't worry, we'll look at sprites later!
|We can use Vblank as a way of slowing down our game... Vblank
occurs when the screen restarts drawing, so happens 60 times a second
(50 on PAL systems)
We can detect Vblank using bit 3 of data read from the Control port, we just read in a byte and test it, if the bit is 1 we're in VBlank.
We can wait until Vblank starts, and ends to ensure our game isn't running faster than 50fps.
| Lesson P6 - Bitmap Functions on
The Amiga is essentially a 'bitmap' based system, we allocate an area of memory to be our screen data, and we can write data into that area to get our pixels on the screen,
However there are some complexities to getting things working, so lets learn how to make it behave!
|The Amiga works in
'Bitplanes'... this is where each byte of data for the screen contains
a single bit of 8 pixels - called a bitplane... 4 of these
bitplanes combined will allow us 16 colors...
The Amiga 500 supports up to 6 bitplanes, We can optionally configure these bitplanes into 2 layers in parallax...
The Amiga can use up to 32 colors in a single layer (5 bitplanes) ... or have two 3 bitplane layers with 8 colors each (odd numbered bitplanes will be layer 1, even numbers will be layer 2)
In these tutorials we'll be defining one 320x200 layer of 16 colors (4 bitplanes)... this is because it will give good 'compatibility' with the Atari ST, and the other systems we're covering in these tutorials.
pixels we want to set:
Bitplanes compared to nibbles
|Word 1||Word 2|
|0||0||0||0||0||0||0||n||n||n||n||n||n||n||n||0||D||D||D||D||D||D||D||D||D||D||D||D||D||D||D||D||Change setting||n= address to Change ($DFFnnn) D=new data for address|
|V||V||V||V||V||V||V||V||H||H||H||H||H||H||H||1||v||v||v||v||v||v||v||v||h||h||h||h||h||h||h||1||wait for pos||V=Vops H=Hpos v=Vpos Compare enable h=hpos compare enable|
|We need our screen and the 'Copperlist' for the co-processor to be contained within the 'Chip Ram'
To ensure this we need to define a 'ChipRAM' section - the Assembler / Linker will create an executable file, and the operating system will ensure this area of the program is in the correct
We're also going to use the command 'CNOP 0,4'... this zero pads the area to a 32 bit boundary - needed for the screen data
Now we have some memory, we can start setting up the screen!
Ram' in the Amiga is the basic ram of the machine (not add on
upgrades)... we need it to do tasks like Graphics and Sound FX...
Our main code probably isn't running in Chip ram, so we can't 'tag' our screen buffer in there - we have to declare proper section, so the Assembler will build the correct executable and the OS will give us our memory
|The first stage of setting up our screen is calling the os, and opening the graphics library ...
we'll use this to turn on the screen, but we'll do all the other screen config by directly manipulating the hardware registers!
You can see the different libraries the Amiga has here ... and the full contents of the Graphics library here
|We're going do the basics of defining the screen size, bitplanes and position.
we need to use the chip registers to do this (see here for the full list)
We're going to set up our 320x200 16 color (4 bitplane) layer,
Next we'll set up the screen position
Finally we want to start the DMA control to handle the screen...
we're now going to set up our copperlist that will define the screen memory and colors!
|We need to define our copperlist, the Coprocessor will use it to draw each frame of our screen.
As mentioned before, the copperlist commands are made up of two words per command,
The first word (2 bytes) is a register number... for example $00e2 is $DFF0E2
The second word (2 bytes) is the new value for the command.
First we'll define the memory location of the 4 bitplanes that make up our screen - they'll be 8000 bytes apart (40x200)
Then we'll define our starting color palette... we'll also remember the memory position of the palette definitions, as we can use it later to change our colors.
The last commands is a command to wait forever ($fffffffe) ... the list will automatically restart when the next screen redraw starts.
When we've defined our copperlist, we load the address of the copperlist into the pointer of the Chip Ram - our screen is finally set up!
|The example here is just creating a single plane, you could have more colors, or more planes with a more advanced set up, but that's beyond the scope of these tutorials - but feel free to play around if you want!|
|Our screen is split into 4
bitplanes, and as the screen is 320 pixels wide (40 bytes) and the
screen is 200 lines tall, then each bitplane will be 8000 pixels apart.
Of course, if we want to set the color of a pixel, we'll have to set all these bitplanes, and we'll see that in our code
|We can see this mimicked in our bitmap copying code...
The byte data of the bitmap are in bitplane format (exported by my AkuSprite Editor)
4 consecutive bytes bytes are copied to each bitplane.
We use the GetScreenPos to calculate the correct memory position from a X,Y position (where X is in Bytes, and Y is in lines)
We also use GetNextLine to move down a line at the end of each line of our bitmap
|The bitmap will be shown to the screen at the position we specified!|
|Want to convert a bitmap for use on the Amiga? The Free & open source AkuSprite Editor can do it for you!
It's included in the sources.7z, so go get it if you want!
|Setting up the screen was hard, but Calculating
a screen position is easy.. all we need to do is multiply our Ypos
by 40 (the width of the screen) and add X , and the base of the
Moving down a line is also easy, we just add 40 to the current position!
course, calling a routine to move down a line is a pretty lousy to do
things if you're just doing an Amiga game, you should just put that
ADDA straight in the loop!
The reason we do the call is we're supporting lots of machines with the common drawing code... THEN it makes sense!
|If we want to slow our game down, a good way is to wait for Vblank (The start of screen redraw)
this will cap our game to 60/50 hz, and keep our game speed under control
We can test for Vblank on the Amiga by testing $DFF004 (VposR)