AMOS AGA - AGE Development Blog (Advanced Graphics Engine for AmosPro / Amiga AGA)
What Is it?
AGE is a bare bones graphics engine / library for the
Amos / AmosPro developers on the
Amiga platform. The library allows the user to perform various graphical effects, but mainly gives the user the ability to the use the Amiga's AGA chipset from AMOS / AMOSPRO.
The project was originally active between
1996 -> 1998, with that version of the library being release around 2000. It hasn't been updated since. Given the age of library, it'd be easy to say why bother, well, the recent updates just clean up the code and make it more user friendly. The previous release examples were
very complicated to follow and virtually impossible to use without low level knowledge. Having said, some new features have been added, but those have mostly been cosmetic.
The changes to the package are in the examples.. There are now example, where there wasn't previously.
Can I use the library under AMIGA emulation ?
Yes, that's how recent updates of the package have been developed. For those without real AMIGA hardware anymore (like myself), there's also package versions of AMOSPRO (WinUAE + AMOS) that be run directly on Windows. Well worth a bit of nostalgia..
Can I use the library from other BASIC languages on AMIGA ?
Yes, you could. The library is presented as a pre-assembled chunk of machine code with AMOS wrapper. Therefore you can use AGE from any language that allows you set the registers and call a function by pointer.
Didn't you write AMOS AGA
Yes; decaded ago now I wrote a collection of simple demos that used AGA in AMOS
https://aminet.net/package/dev/amos/AmosAGA (https://aminet.net/package/dev/amos/AmosAGA)
Home Page?
AGE From Home Page (http://www.underwaredesign.com/?page=programs.A-G-E-) (NOTE:
OLD 2000 Version )
Beta Downloads?
AGE V1.02 BETA #1 (http://www.underwaredesign.com/forums/index.php?topic=3814.msg25349#msg25349) (21st,Apr,2012)
Videos
Work In Progress.
Given the age of the library, I'm
not going to be updating it on a regular basis, the following updates just make the library a lot more user friendly. Firstly the library now comes as an separate AMOS file. So the user just includes the file into their project (at the top of the code) and then is ready to use AGE function bellow that.
Some of functions/procedure names have been changed and well as some helper functions have been added. As new functionality is added it'll be documented here.
Function List.
While the library supports
PLANAR,
INTERLEAVED PLANAR and
CHUNKY pixel formats, not ALL drawing functions do.
System AGE_ALLOC_RESOURCES[SCRNS,COPS,BLOCKS,BANKS,FONTS,FILECACHE,DATACACHE] ; This function basically opens the library so you can use it. The library was designed to be fairly flexible in terms of resources, so rather than it allocate memory for the various resource tables. You'll need to supply this function withe the sizes of various buffers the library will use. When you call it, this allocates the base the AGE resource structure the entire library then uses.
SCRNS = Number of Screens you want
COPS = Number of Coppers you want
BLOCKS = Numbers of Blocks banks you want
BANKS = Number of banks
FONTS = Number of fonts
FILECACHE = Size of temporary file buffer for loading.
DATACACHE = Set users required data cache size
AGE_TAKE_SYSTEM[COPADDR] ; This function takes over system and sets up the low level machine state. The function expects the address of the COPPER List to install upon execution.
AGE_RESTORE_SYSTEM ; Restore system state after it's been taken over.
AGE_FORBID_TASKING ; Disable the Amiga OS from multi tasking
AGE_PERMIT_TASKING ; Allow the Amiga OS to multi task
Screen AGE_OPEN_SCREEN[SCRN,WIDTH,HEIGHT,DEPTH,TYPE] ; Creates a screen of width/height/depth, of particular type. Supports Planar / Interleaved & Chunky screen types. The screen default to being created in chip memory, but can be forced into Fast.
AGE_OPEN_CHUNKY_SCREEN[SRCN,WIDTH,HEIGHT] ; Creates a 8bit chunky screen in fast memory.
AGE_DELETE_SCREEN[SRCN] ; Releases a screens memory. Beware that if this screen is the current copper list screen you'll get undefined results.
AGE_LOAD_IFF_TO_SCREEN[FILENAME$,SCRN] ; Loads an IFF file into a previously created screen. Supports 1 to 8bit IFF images
AGE_SAVE_IFF[FILENAME$,SCRN] ; Save screen to disk as IFF file.
AGE_EXAMINE_IFF[FILENAME$ ; Queries IFF file for it's size information. The function returns the Width/Height/Depth in the dregs(0),dregs(1),dregs(2)
AGE_SET_SCREEN[SCRN] ; Make the library direct rendering to this screen from now on.
AGE_SCREEN_VIEWPORT[X1,Y1,X2,Y2] ; Set the viewport (Render area) of the current output screen. This lets you clip rendering to within a certain care of the screen.
AGE_RESTORE_SCREEN_VIEWPORT ; Restore the view port to the screens original size.
AGE_GET_SCREEN_VIEWPORT ; The screens current view port size. Values returns in dreg 0,1,2,3
AGE_GET_BITPLANE_ADDR[SCRN,BP] ; Get Address of bit plane within this screen.
AGE_GET_SCREEN_WIDTH[SCRN] ; Get width of screen. Param or dreg(0)=result
AGE_GET_SCREEN_HEIGHT[SCRN] ; Get height of screen. Param or dreg(0)=result
AGE_GET_SCREEN_DEPTH[SCRN] ; Get depth of screen. Param or dreg(0)=result
AGE_GET_SCREEN_TYPE[SCRN] ; Get type of screen. Param or dreg(0)=result
Copper AGE_CREATE_COPPER[Index, ScreenIndex, BurstMode, BurstModulo] ; Creates a standard copper list in chip memory. The view settings are is based upon a screen you provide
AGE_DELETE_COPPER[Index] ; Delete a copper list from chip memory.
AGE_SHOW_COPPER[Index] ; Set the copper hardware to view your copper list. Sme as AGE_SET_COPPER, except this version flushs the display hardware.
AGE_SET_COPPER[Index] ; Set the copper hardware to view your copper list
AGE_REFRESH_COPPER_PALETTE[COPPER_INDEX,PAL_POINTER] ; Update the colour table in the copper with a user defined list of 256 32bit RGB colour values.
AGE_GET_COPPER_PTR[COPPER_INDEX] ; This functions returns a pointer to the copper list in chip memory. You can modify it all you want. The only limit is that copper lists allocated by the library, must be smaller than
4096 bytes..
Graphics AGE_DOT[x,y] ; Draw DOT in current ink colour (CLIPPED) to current surface (Supports PLANAR / CHUNKY)
AGE_DOTC[x,y,colour] ; Draw DOT in user defined ink colour (CLIPPED) to current surface
AGE_DOT_NC[x,y] ; Draw DOT in current ink colour (NO CLIPPED) to current surface (Supports PLANAR / CHUNKY)
AGE_DOTC_NC[x,y,colour] ; Draw DOT in user defined ink colour (NO CLIPPED) to current surface
AGE_LINE[x1,y1,x2,y2] ; Draw Lines in current ink colour (CLIPPED) (Supports PLANAR / CHUNKY )
AGE_LINEC[x1,y1,x2,y2] ; Draw Lines in user defined ink colour (CLIPPED)
AGE_BOX[X1,Y1,X2,Y2] ; Draws a filled rectangle in current ink colour. (Supports PLANAR / INTERLEAVED PLANAR & CHUNKY)
AGE_BOXC[X1,Y1,X2,Y2,PCOL] ; Draws a filled rectangle in user defined colour. (Supports PLANAR & CHUNKY)
AGE_DRAW_FILLED_BOX[X1,Y1,X2,Y2,PLANEMASK] ; Draws a filled rectangle on the user defined planes. (Supports PLANAR)
AGE_DRAW_CLEAR_BOX[X1,Y1,X2,Y2,PLANEMASK] ; Clears a filled rectangle on the user defined planes. (Supports PLANAR)
AGE_DRAW_SHADE_BOX[X1,Y1,X2,Y2,C1,C2,C3,C4] ; Grads a gouraud shaded rectangle to the current screen (Supports Chunky)
AGE_CIRCLE[X,Y,RAdius] ; Draws a filled circle in current ink colour. (Supports PLANAR & CHUNKY)
AGE_CIRCLEC[X,Y,RAdius,PCOL] ; Draws a filled circle in user defined colour. (Supports PLANAR & CHUNKY)
AGE_COPY_RECT[SrcScreen,X1,Y1,X2,Y2,DestScreen,DestX,DestY] ; Copy a section from the source image to the destination. (Supports PLANAR & CHUNKY)
AGE_COPY_RECT_QUEUE[QUERE_POINTER, X_OFFSET,Y_OFFSET, NUMB_OF_ITEMS_IN_QUEUE] ; Render a list of queued copy rect's. The output location can be displaced using with X & Y offsets. The structure is expected to be 16 bytes wide (16 bytes per queue item) (Supports PLANAR & CHUNKY)
AGE_SET_RECT_QUEUE[QUERE_POINTER, INDEX,SrcScreen,X1,Y1,X2,Y2,DestScreen,DestX,DestY] ; This is a wrapper function to set the source rect and destination position of the rect to be copied. The Function requires a user allocated buffer big enough to fit the queue data. If you wanted to store 50 items, then you'd need to allocate at least 50*16 (16 bytes per item) for the buffer. Each item in the queue is accessed via an Index, ranging from 0 to Number_Of_items -1
AGE_TRI[x1,y1,x2,y2,x3,y3] ; Draws a triangle in the current INK colour. (Chunky)
AGE_TRIC[x1,y1,x2,y2,x3,y3,Colour] ; Draws a triangle in a user defined colour (Chunky)
AGE_QUADC[x1,y1,x2,y2,x3,y3,x4,y4,Colour] ; Draws a 4 sided polygon in user defined colour, the vertex given to the function must form a CONVEX polygon (Chunky)
AGE_GOURAUDTRI[x1,y1,Colour1,x2,y2,Colour2,x3,y3,Colour3] ; Draws a gouraud shaded triangle to the current screen. (Chunky)
AGE_GOURAUDQUAD[x1,y1,Colour1,x2,y2,Colour2,x3,y3,Colour3,x4,y4,Colour4] ; Draws a gouraud shaded 4 sided convex polygon to the current screen. (Chunky)
Fonts AGE_LOAD_FONT[FILENAME$,INDEX] ; Load a Font into a available font buffer.
AGE_DELETE_FONT[Index] ; Delete a front from memory
AGE_FONT_PLANE_MASK[INDEX,MASK] ; Specify which bitplanes the font should write to when drawn. Defaults to %11111111 (All Planes)
AGE_GET_FONT_PLANE_MASK[INDEX[Index] ; Get the bitplane mask this font is using.
AGE_GET_FONT_HEIGHT[INDEX] ; Get the fonts overall height.
AGE_SET_FONT[INDEX] ; Set default font for rendering functions like AGE_PRINT
AGE_GET_FONT ; Get the current output font if any.
AGE_INK[ColourIndex] ; Set the current INK colour for rendering functions.
AGE_GET_INK ; Set the current INK colour for rendering functions.
AGE_SET_CURSOR ; Set the current cursor position (X/Y) coordinates.
AGE_PRINT[t$] ; Prints the String T$ at current cursor position, in the current colour and font. NOTE: Only seem to support rendering to PLANAR formatted screens
AGE_TEXT[T$,X,Y,C] ; Render text at any position on the current screen. Using the current font.
NOTE: PRINT & TEXT functions truncate the X coordinate to nearest byte when rendering, and there only seems to be clipping on the vertical axis.
C2p (Chunky To Planar) AGE_C2P[SourceChunkyScreen,TargetPlanarScreen] ; Convert the chunky formatted source image to an 8bit planat screen.
AGE_C2P_CLS[SourceChunkyScreen,TargetPlanarScreen] ; Convert the chunky formatted source image to 8bit planar screen with chunky CLS (colour 0).
Colours RGB[R,G,B] ; Merges the three 8Bit R,G,B values into packed 32bit colour value.
RGBR[ThisRGB] ; Get the 8Bit Red Value from colour , result in Param
RGBG[ThisRGB] ; Get the 8Bit Green Value from colour , result in Param
RGBB[ThisRGB] ; Get the 8Bit Blue Value from colour , result in Param
RGB_24TO12[RGB] ; Convert 24bit RGB value into 12Bit RGB value, result in Param
RGB_12TO24[RGB] ; Convert 12bit RGB value into 24Bit RGB value, result in Param
RGB_ALPHA_BLEND[RGB1,RGB2,SCALE#] ; Alpha Blend Two RGB colours, scale range 0.0 to 1.0, result in Param
RGB_INT_ALPHA_BLEND[RGB1,RGB2,INTSCALE] ; Alpha Blend Two RGB colours, IntScale Range 0 To 255, result in Param
RGB_ALPHA_ADD[RGB1,RGB2] ; Alpha Add Two RGB colours, result in Param
RGB_ALPHA_SUB[RGB1,RGB2] ; Alpha Subtract Two RGB colours, result in Param
RGB_FADE[THISRGB,SCALE#] ; Scale the input RGB colour. (Scale range 0 to 1.0) result in Param
RGB_INTFADE[THISRGB,IntSCALE] ; Scale the input RGB colour. (IntScale range 0 to 255) result in Param
Blitter AGE_OWN_BLITTER ; Take exclusive control over the blitter chip.
AGE_DISOWN_BLITTER ; Release control over the blitter
AGE_WAIT_BLIT ; Wait for blitter to complete it's current work.
Banks AGE_CREATE_BANK[BANK,SIZE] ; CReate a bank of SIZE (in bytes)
AGE_DELETE_BANK[BANK] ; Deletes a BANK from memory
AGE_LOAD_BANK[FILENAME$,BANK] ; Load Data directly to a Bank
AGE_GET_BANK_PTR[BANK] ; Returns the address (pointer) of the first byte in a bank
AGE_GET_BANK_SIZE[BANK] ; Returns the size in bytes of a bank
You can use the
Amos Peek/Poke commands to modify the banks content at will
Fixed Point Math / Trig Functions AGE_COS[ANGLE] ; Cosine of angle (in degrees), returns
fixed point 16:16 integer AGE_SIN[ANGLE] ; Sine of angle (in degrees), returns
fixed point 16:16 integer AGE_COSRADIUS[ANGLE] ; Cosine of angle (degrees) * RADIUS, returns
fixed point 16:16 integer AGE_SINRADIUS[ANGLE] ; Sine of angle (degrees) * RADIUS, returns
fixed point 16:16 integer AGE_POLAR[ANGLE] ; returns
X / Y in dreg(0) and dreg(1) returns
fixed point 16:16 integer AGE_SINRADIUS[ANGLE] ; Sine of angle (degrees) * RADIUS, returns
fixed point 16:16 integer AGE_ROTATE2D[ANGLE,X,Y] ; Rotate a 2d coordinate by ANGLE degrees. Result returned in D0/D1 registers.
AGE_ROTATE2D_BATCH[SRCPTR,SRCVERTEXMODULO,DESTPTR,DESTVERTEXMODULO,METHOD,ANGLE,VERTEXCOUNT]
; 2D Rotate a set of points. See Here for More Info (http://www.underwaredesign.com/forums/index.php?topic=3814.msg25346#msg25346)
ANGLES are wrapped to 360 degrees internally. To convert from fixed point to Integer we divide the value by $10000. Some functions will do this for you, others won't to keep the precision.
AGE Example - Loading 256 Colour Picture In AmosPro In very short this video we see the AGE library wrapper being used from AmosPRO. The demo frame work sets up the library, create a screen, loads the 8bit (256 colour) IFF, creates a copper list and then displays it.
Developed By:
https://www.underwaredesign.com
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - Loading 256 Colour IFF's
'
' By
'
' By Kevin Picone
'
' Last Updated - 14th, Mar, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V064.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / INTERLEAVED AGE screen in Chip Memory
' -----------------------------------
TYPE=AGE_LOWRES
TYPE=TYPE+AGE_INTERLEAVED
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
' -----------------------------------
' Load IFF into this screen.
' -----------------------------------
FILE$=APPPATH$+"GFXFILES/PICTURES/DRAGONAA.IFF"
AGE_LOAD_IFF_TO_SCREEN[FILE$,0]
' -----------------------------------
' Create a standard/ simple copper list for viewing this screen.
' -----------------------------------
AGE_OPEN_STANDARD_COPPER[0,0,3,8]
' -----------------------------------
' Create copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[0]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
' -----------------------------------
' Direct ALL RENDERING To OUR Screen
' -----------------------------------
AGE_SET_SCREEN[0]
' -----------------------------------
' Wait for a key
' -----------------------------------
Wait Key
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
AGE Clean Up
The original library was written using AsmOne on the my Amiga 1200, but sadly this is really unstable under emulation, so in order to update the library i've had to change assemblers. Which means running the code through a make ship translator written in PlayBASIC (http://www.playbasic.com). Even so, it still took a few hours to get it assembling under PHXASS. So the build process now, is editing code on the PC side, switching to WinUAE and assembly through the command line. A little messy, but it's fairly comfortable really once you get going.
While looking through the command set of the library, there's some obvious pitfalls in the commands, by that i mean, there's some missing functionality to tie some parts together better. One such issue, was that you couldn't update the display copper colour list once it'd be created from the parent screen. Might not sound like a big deal, but it meant you couldn't change the palette colours. So I've added a function to write a custom palette back into the copper list on demand.
Here's an example that grabs the palette from the source screen, then fades it out after hitting a key.
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - Loading 256 Colour IFF's With Palette fade
'
' By
'
' By Kevin Picone
'
' Last Updated - 16th, Mar, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V064.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / INTERLEAVED AGE screen in Chip Memory
' -----------------------------------
TYPE=AGE_LOWRES
TYPE=TYPE+AGE_INTERLEAVED
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
' -----------------------------------
' Load IFF into this screen.
' -----------------------------------
FILE$=APPPATH$+"GFXFILES/PICTURES/DRAGONAA.IFF"
AGE_LOAD_IFF_TO_SCREEN[FILE$,0]
' -----------------------------------
' Read the Colour Palette from the this screen
' -----------------------------------
Dim CURRENT_PALETTE(256)
AGE_SCREEN_COPY_PALETTE_TO_ARRAY[0,Varptr(CURRENT_PALETTE(0))]
' -----------------------------------
' Create a standard / simple copper list for viewing this screen.
' -----------------------------------
AGE_OPEN_STANDARD_COPPER[0,0,3,8]
' -----------------------------------
' Create copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[0]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
' -----------------------------------
' Direct ALL RENDERING To OUR Screen
' -----------------------------------
AGE_SET_SCREEN[0]
' -----------------------------------
' Wait for a key
' -----------------------------------
Wait Key
' -----------------------------------
' FAde Screen Out
' -----------------------------------
Dim TEMP_PALETTE(256)
LEVEL=100
Repeat
LEVEL=LEVEL-2
SCALE#=LEVEL/100.0
' --------------------------------------------------------
' Fade all the colours in our copy of the screens palette
' --------------------------------------------------------
For LP=0 To 255
' grab the screens original palette colour
C=CURRENT_PALETTE(LP)
' fade this colour by the required amount
RGB_FADE[C,SCALE#]
' store the new colour in a second temp array of palette colours
TEMP_PALETTE(LP)=Param
Next
AGE_WAIT_TOP_OF_FRAME
' get a pointer to the Faded array of colour values
PAL_POINTER=Varptr(TEMP_PALETTE(0))
' Copy this array of colour values to this copper list
AGE_REFRESH_COPPER_PALETTE[0,PAL_POINTER]
Until LEVEL<1
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
Just picking through the library, there does seem to be some command sets that require specially formatted external data such as FONTS and MAPS. I haven't looked at the block map stuff, but fonts seems to have some problems in the updated version of the Library. Hopefully that's an easy fix, as if it's not, it may well stay broken. We'll see.
AGE - Double Buffering / Animation Been picking through the library in my spare time, it's a bit hit and miss as to some things. Took a while to set up a working double buffering example, not because the buffer swapping wasn't working, it turned out that the LINE function has a bug in it, where it will only draw to SCREEN 0. So you can draw to one frame buffer and not the other.
Anyway so here we have simple set up example. The demo creates two frame buffers and two copper lists, a variable CURRENT_BUFFER is the index of the current SCREEN we're rendering to, so while we're drawing to CURRENT_SCREEN, we show the other screens copper list. The main loop is of the demo is copying a 256 colour picture to the current screen, then draws some orbiting filled circles over the top.
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - DOUBLE BUFFER / ANIMATION
'
' By
'
' By Kevin Picone
'
' Last Updated - 19th, Mar, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V067.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / INTERLEAVED AGE screen in Chip Memory '
' -----------------------------------
TYPE=AGE_LOWRES
' TYPE=TYPE+AGE_INTERLEAVED
TYPE=TYPE+AGE_PLANAR
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
AGE_OPEN_SCREEN[1,320,256,8,TYPE]
CURRENT_BUFFER=0
' -----------------------------------
' Load IFF into this a temp screen.
' -----------------------------------
FILE$=APPPATH$+"GFXFILES/PICTURES/DRAGONAA.IFF"
AGE_OPEN_SCREEN[3,320,256,8,TYPE]
AGE_LOAD_IFF_TO_SCREEN[FILE$,3]
' copy the palette from the backdrop picture in the chip buffers
AGE_SCREEN_COPY_PALETTE[3,0]
AGE_SCREEN_COPY_PALETTE[3,1]
' -----------------------------------
' Create two copper lists for viewing our screens.
' -----------------------------------
AGE_CREATE_COPPER[0,0,3,8]
AGE_CREATE_COPPER[1,1,3,8]
' -----------------------------------
' Set copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[1-CURRENT_BUFFER]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
' -----------------------------------
' Direct ALL RENDERING To OUR Screen
' -----------------------------------
AGE_SET_SCREEN[CURRENT_BUFFER]
' -----------------------------------
' Load a Font
' -----------------------------------
FONTS$=APPPATH$+"gfxfiles/fonts/"
AGE_LOAD_FONT[FONTS$+"Alex8.font",2]
AGE_SET_FONT[2]
' -----------------------------------
'
' -----------------------------------
Degree
Do
' -------------------------------------------------
' Swap Buffers
' -------------------------------------------------
CURRENT_BUFFER=1-CURRENT_BUFFER
AGE_SET_SCREEN[CURRENT_BUFFER]
AGE_SET_COPPER[(1-CURRENT_BUFFER)]
AGE_WAIT_TOP_OF_FRAME
' -------------------------------------------------
' Copy the temp image to the current render buffer
' -------------------------------------------------
AGE_COPY_SCREEN[3,0,0,320,256,CURRENT_BUFFER,0,0]
' -------------------------------------------------
' Draw spinning circles
' -------------------------------------------------
RENDER_STAR[160,128,BASEANGLE]
BASEANGLE=(BASEANGLE+1) mod 360
' ---------------------------
' Render some text on the scene
' ---------------------------
AGE_TEXT["Double Buffering",10,10,1]
' ---------------------------
' Check for key press
' ---------------------------
KEYPRESS$=Inkey$()
If KEYPRESS$=" " Then Exit
Loop
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
End
Procedure RENDER_STAR[X,Y,BASEANGLE]
' -----------------------------------------------------------------
' Draw a bunch of rotating circles in orbit around the screen center
' -----------------------------------------------------------------
AGE_OWN_BLITTER
For ANGLE=0 To 359 Step 30
ANGLE2=BASEANGLE+ANGLE
' ANGLE2=ANGLE mod 360
X2=X+Cos(ANGLE2)*100
Y2=Y+Sin(ANGLE2)*100
Inc INDEX
AGE_INK[INDEX]
AGE_CIRCLE[X2,Y2,20]
Next
AGE_DISOWN_BLITTER
End Proc
AGE - Gouraud Shaded Cube in Amos Pro (AGA) Tonights little goal was to get the C2P side of library all tested, so I can throw together some examples to wrap it all up... But you know as soon as you make plans, the ground shifts and another adjustment is required. On this occasion, it turns out the C2p conversion routines in the library weren't working anymore after the port. Was initially thinking the issue was just me not remembering how to set up the buffers anymore (it's been over 12 years after all all), but after some trail and error it turns out the Chunky to planar conversion routines weren't working. Which after a bit more detective work, the fault was caused by the new assembler optimizing out what it through was redundant offsets, but that's fixed now.
So bellow we have a picture of an AMOS PRO remake of the gouraud shaded cube demo (the demo found in the PLLBC2p library). Now granted it's not going to be as fast as the native assembly version, given that's doing more work than that demo, but it's still fairly quick when running under JIT enabled emulation, without even compiling the demo. Moreover, the library doesn't have any built in rotation support, so all the rotation/ projection and back face culling are running in little old AMOS.
Will post a video later..
AGE Gouraud Cube (AmosPro / Amiga AGA) In this video, I'm using the AGE library from AmosPRO to draw a chunky 8Bit AGA scene with gouraud shaded cube. The program is drawing the 320*256 backdrop picture, some orbiting circles and the gouraud shaded cube each frame. All the grunt work is done by the library, expect the 3D stuff (rotation/projection/back face culling) which is done in little old Amos.
The clip is recording running from WinUAE with no jit and without compiling the Amos example. It runs surprisingly quickly with JIT, even the Amos Interpreter, so it should give those Amos fans a bit of fun.
Developed By:
https://www.underwaredesign.com
Here's the AmosPro source code to this demo.
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - GOURAUD CUBE
'
' By
'
' By Kevin Picone
'
' Last Updated - 21st, Mar, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V069.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / PLANAR AGE screens in Chip Memory
' -----------------------------------
TYPE=AGE_LOWRES+AGE_PLANAR
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
AGE_OPEN_SCREEN[1,320,256,8,TYPE]
CURRENT_BUFFER=0
' -----------------------------------
' CReate CHUNKY temp screen.
' -----------------------------------
CHUNKY_BUFFER=3
AGE_OPEN_CHUNKY_SCREEN[CHUNKY_BUFFER,320,256]
' -----------------------------------
' Load IFF into another chunky screen.
' -----------------------------------
CHUNKY_PICTURE=4
FILE$=APPPATH$+"GFXFILES/PICTURES/DRAGONAA_156.IFF"
AGE_OPEN_CHUNKY_SCREEN[CHUNKY_PICTURE,320,256]
AGE_LOAD_IFF_TO_SCREEN[FILE$,CHUNKY_PICTURE]
' Fill the palette with a gradient from colours 256 to 255
MAKE_PALETTE[CHUNKY_PICTURE,$443355,$FFBB88,156,255]
' Copy the pictures palette to the chunk buffers
AGE_SCREEN_COPY_PALETTE[CHUNKY_PICTURE,0]
AGE_SCREEN_COPY_PALETTE[CHUNKY_PICTURE,1]
' -----------------------------------
' Create standard / simple copper list for viewing our screens.
' -----------------------------------
AGE_CREATE_COPPER[0,0,3,8]
AGE_CREATE_COPPER[1,1,3,8]
' -----------------------------------
' Set copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[1-CURRENT_BUFFER]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
Degree
Gosub _INIT_3D
Do
' -------------------------------------------------
' Swap Buffers
' -------------------------------------------------
AGE_C2P_SCRN_CLS[CHUNKY_BUFFER,CURRENT_BUFFER]
CURRENT_BUFFER=1-CURRENT_BUFFER
AGE_SET_COPPER[(1-CURRENT_BUFFER)]
AGE_WAIT_TOP_OF_FRAME
AGE_SET_SCREEN[CHUNKY_BUFFER]
AGE_COPY_SCREEN[CHUNKY_PICTURE,0,0,320,256,CHUNKY_BUFFER,0,0]
' -------------------------------------------------
' Copy the temp image to the current render buffer
' -------------------------------------------------
RENDER_STAR[160,128,BASEANGLE]
BASEANGLE=(BASEANGLE+1) mod 360
' -------------------------------------------------
' Render 3D Scene
' -------------------------------------------------
Gosub _UPDATE_3D
KEYPRESS$=Inkey$()
If KEYPRESS$=" " Then Exit
Loop
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
End
' ---------------------------------------------------------------
' -----------------------------------------------------------
' -------------->> SUB ROUTINES & FUNCTIONS <<-------------
' -----------------------------------------------------------
' ---------------------------------------------------------------
_INIT_3D:
'Define our number system. In this demo i'm using 24:8
' (24 bit whole part, 8 bit fractional) fixed point
Global ACC
ACC=256
' Vertex Buffer for the object, XYZ order groups of 3
Dim VERTEX_BUFFER(2000)
' Rotated vertex buffer
Dim ROTATED_VERTEX_BUFFER(2000)
' Face list for Object
Dim FACE_LIST(1000)
' CReate SIN/COS Tables
Dim CS(720)
Dim SN(720)
Shared CS()
Shared SN()
INIT_MATH_TABLES[720]
' CReate a Cube mesh in the vertex buffer array
PTR=Varptr(VERTEX_BUFFER(0))
INIT_CUBE_VERTEX_BUFFER[PTR,BX_WIDTH,BX_HEIGHT,BX_DEPTH]
PTR=Varptr(FACE_LIST(0))
INIT_CUBE_FACE_LIST[PTR]
FACECOUNT=Param
Return
' ---------------------------------------------------------------
' -----------------------------------------------------------
' -------------->> UPDATE 3D SCENE <<-------------
' -----------------------------------------------------------
' ---------------------------------------------------------------
_UPDATE_3D:
SRCPTR=Varptr(VERTEX_BUFFER(0))
DESTPTR=Varptr(ROTATED_VERTEX_BUFFER(0))
VERTS=8
ROTATE_POINTS[SRCPTR,DESTPTR,8,160,128,300,ALPHA,BETA,GAMMA]
ALPHA=(ALPHA+1) mod 360
BETA=(BETA+2) mod 360
GAMMA=(GAMMA+3) mod 360
VERTCOUNT=(VERTS-1)*3
For LP=0 To VERTCOUNT Step 3
X=ROTATED_VERTEX_BUFFER(LP)
Y=ROTATED_VERTEX_BUFFER(LP+1)
AGE_CIRCLEC[X,Y,5,100]
Next
COUNT=(FACECOUNT-1)*3
For LP=0 To COUNT Step 3
V1=FACE_LIST(LP)*3
V2=FACE_LIST(LP+1)*3
V3=FACE_LIST(LP+2)*3
X1=ROTATED_VERTEX_BUFFER(V1)
Y1=ROTATED_VERTEX_BUFFER(V1+1)
X2=ROTATED_VERTEX_BUFFER(V2)
Y2=ROTATED_VERTEX_BUFFER(V2+1)
X3=ROTATED_VERTEX_BUFFER(V3)
Y3=ROTATED_VERTEX_BUFFER(V3+1)
AX=X2-X1
AY=Y2-Y1
BX=X3-X1
BY=Y3-Y1
If((AX*BY)-(BX*AY))<0
Z1=ROTATED_VERTEX_BUFFER(V1+2)
Z2=ROTATED_VERTEX_BUFFER(V2+2)
Z3=ROTATED_VERTEX_BUFFER(V3+2)
C1=(Z1/500.0)*100
C2=(Z2/500.0)*100
C3=(Z3/500.0)*100
Add C1,156
Add C2,156
Add C3,156
AGE_GOURAUDTRI[X1,Y1,C1,X2,Y2,C2,X3,Y3,C3]
End If
Next
Return
' ---------------------------------------------------------------
' -----------------------------------------------------------
' -------->> INIT MATH (COS/SIN) Tables <<----------
' -----------------------------------------------------------
' ---------------------------------------------------------------
Procedure INIT_MATH_TABLES[SIZE]
For LP=0 To SIZE
CS(LP)=Cos(LP)*ACC
SN(LP)=Sin(LP)*ACC
Next
End Proc
' --------------------------------------------------------------------
' ROTATE POINTS
' --------------------------------------------------------------------
Procedure ROTATE_POINTS[SRCPTR,DESTPTR,VERTS,XPOS,YPOS,ZPOS,ALPHA,BETA,GAMMA]
AX=ALPHA
AY=BETA
AZ=GAMMA
' cos&sin alpha pre calcs
CA=CS(AX)
SA=SN(AX)
' Cos & Sin Beta pre calc
CB=CS(AY)
SB=SN(AY)
' Cos & Sin Gamma pre calcs
CG=CS(AZ)
SG=SN(AZ)
XPOS2=XPOS*ACC
YPOS2=YPOS*ACC
For I=0 To VERTS
X=Leek(SRCPTR)
Y=Leek(SRCPTR+4)
Z=Leek(SRCPTR+8)
SRCPTR=SRCPTR+12
Y2=((Y*CA)+(Z*SA))/ACC
Z=((Z*CA)-(Y*SA))/ACC
' Y=Y2
X2=((X*CB)+(Z*SB))/ACC
Z=((Z*CB)-(X*SB))/ACC
' X=X2
Y=(Y2*CG)+(X2*SG)
X=(X2*CG)-(Y2*SG)
Add Z,ZPOS
Loke DESTPTR,(X/Z)+XPOS
Loke DESTPTR+4,(Y/Z)+YPOS
Loke DESTPTR+8,Z
DESTPTR=DESTPTR+12
Next I
End Proc
Procedure INIT_CUBE_VERTEX_BUFFER[VERTBUFFERPTR,BX_WIDTH,BX_HEIGHT,BX_DEPTH]
BX_WIDTH=120
BX_HEIGHT=120
BX_DEPTH=120
DESTPTR=VERTBUFFERPTR
For Z=1 To -1 Step -2
ZPOS=(BX_DEPTH/2)*(Z)
For Y=-1 To 1 Step 2
YPOS=(BX_HEIGHT/2)*(Y)
For X=-1 To 1 Step 2
XPOS=(BX_WIDTH/2)*(X)
Loke DESTPTR,XPOS
Loke DESTPTR+4,YPOS
Loke DESTPTR+8,ZPOS
DESTPTR=DESTPTR+12
Next X
Next Y
Next Z
End Proc
Procedure INIT_CUBE_FACE_LIST[FACEBUFFERPTR]
PTR=FACEBUFFERPTR
' front
SET_FACE[PTR,0,1,3] : Add PTR,12
SET_FACE[PTR,0,3,2] : Add PTR,12
' Back
SET_FACE[PTR,5,4,6] : Add PTR,12
SET_FACE[PTR,5,6,7] : Add PTR,12
' top
SET_FACE[PTR,4,5,1] : Add PTR,12
SET_FACE[PTR,4,1,0] : Add PTR,12
' bottom
SET_FACE[PTR,2,3,7] : Add PTR,12
SET_FACE[PTR,2,7,6] : Add PTR,12
' left
SET_FACE[PTR,0,2,6] : Add PTR,12
SET_FACE[PTR,0,6,4] : Add PTR,12
' right
SET_FACE[PTR,1,5,7] : Add PTR,12
SET_FACE[PTR,1,7,3] : Add PTR,12
FACECOUNT=12
End Proc[FACECOUNT]
Procedure SET_FACE[PTR,V1,V2,V3]
Loke PTR,V1
Loke PTR+4,V2
Loke PTR+8,V3
End Proc
Procedure RENDER_STAR[X,Y,BASEANGLE]
AGE_INK[1]
' -----------------------------------------------------------------
' Draw a bunch of rotating circles in orbit around the screen center
' -----------------------------------------------------------------
For ANGLE=0 To 359 Step 20
ANGLE2=BASEANGLE+ANGLE
' ANGLE2=ANGLE mod 360
X2=X+Cos(ANGLE2)*100
Y2=Y+Sin(ANGLE2)*100
AGE_CIRCLE[X2,Y2,20]
Inc INDEX
AGE_INK[INDEX]
Next
End Proc
Procedure MAKE_PALETTE[THISSCREEN,RGB1,RGB2,INDEX_START,INDEX_END]
RANGE#=INDEX_END-INDEX_START
For LP=0 To RANGE#
SCALER#=LP/RANGE#
RGB_ALPHA_BLEND[RGB1,RGB2,SCALER#]
AGE_SCREEN_SET_PALETTE_COLOUR[THISSCREEN,INDEX_START+LP,Param]
Next
End Proc
hmm nice pictures =)
AGE - 300 triangle Gouraud Donut (Torus) in Amos Pro ( AGA) This is only a small step from the previous demo, here we're just upping the vertex and polygon counts dramatically, from the humble cube of 6 verts and 12 polygons (triangles), to a 300 triangle torus.. While the scene / polygon count are old hat for assembly programmers on the AMIGA, I don't recall ever seeing anything in AMOS do this, so it's likely to be world first in AMOS anyway.
The demo is doing all the 3D worlk in interpreted AMOS, so it's rotating / projecting and rotating the 150 vertexes, back facing and rendering the 300 faces (approximate 150 odd visible faces), the drawing all AGE obviously.. But it shows that you can certainly have a bit of fun with the library if you put your mind to it.
AGE- Copy Rect / Copy Rect Queue Still making my way through the commands when free time appears, fixed a number of little issues here and there. Most of the changes have been to function names or adding the odd little helper function. In the older version of the library, there's a copy image / rect function, with a long but complete name, while descriptive, it wasn't practical. So that's been renamed to
AGE_COPY_RECT. This function copies 'blocks' of graphics from one screen surface to another. Now since we're running the library from interpreted AMOS, you'll notice there's some QUEUED versions of functions also. Basically, these allows us to set to list of things to draw as batch.
In the example bellow we're using the Copy Rect Queue function to create a randomized scrolling block map. To build the queue, we need to allocate some memory of suitable size, here i'm using an array but you can use a bank or whatever. Each item in the queue is 16 bytes, so to store a 100 items in the queue you'd allocate 100*16 bytes. To write to the queue there's a helper function called
AGE_SET_RECT_QUEUE which requires the pointer to the first item in the queue, the Offset this item should be stored at, then Screen Index, source rect and destination and location. For this example it's just randomly picking 16*16 blocks from the dragon picture.
Now to help avoid some Amos overhead, we can draw the queue with an X and Y offset. So to make the scene scroll, we're just drawing the queue items offset from their output location.
Set Buffer 100
' *=-------------------------------------------------------------------=*
'
' AGE - Copy Rect Queues (Block Map Example)
'
' By
'
' By Kevin Picone
'
' Last Updated - 28th, Mar, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V071.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / PLANAR AGE screens in Chip Memory
' -----------------------------------
TYPE=AGE_LOWRES+AGE_PLANAR
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
AGE_OPEN_SCREEN[1,320,256,8,TYPE]
CURRENT_BUFFER=0
' -----------------------------------
' CReate Load IFF into this a temp screen.
' -----------------------------------
CHUNKY_BUFFER=3
AGE_OPEN_CHUNKY_SCREEN[CHUNKY_BUFFER,320,256]
' -----------------------------------
' Load IFF into this a temp screen.
' -----------------------------------
CHUNKY_PICTURE=4
FILE$=APPPATH$+"GFXFILES/PICTURES/DRAGONAA_156.IFF"
AGE_OPEN_CHUNKY_SCREEN[CHUNKY_PICTURE,320,256]
AGE_LOAD_IFF_TO_SCREEN[FILE$,CHUNKY_PICTURE]
' copy the palette from the backdrop picture in the chip buffers
AGE_SCREEN_COPY_PALETTE[CHUNKY_PICTURE,0]
AGE_SCREEN_COPY_PALETTE[CHUNKY_PICTURE,1]
' -----------------------------------
' Create standard / simple copper list for viewing our screens.
' -----------------------------------
AGE_CREATE_COPPER[0,0,3,8]
AGE_CREATE_COPPER[1,1,3,8]
' -----------------------------------
' Set copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[1-CURRENT_BUFFER]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
Degree
' -------------------------------------------------
' Init the scene
' -------------------------------------------------
Gosub _CREATE_RECT_QUEUE
AGE_SET_SCREEN[CHUNKY_BUFFER]
Do
' -------------------------------------------------
' Swap Buffers
' -------------------------------------------------
AGE_C2P[CHUNKY_BUFFER,CURRENT_BUFFER]
CURRENT_BUFFER=1-CURRENT_BUFFER
AGE_SET_COPPER[(1-CURRENT_BUFFER)]
AGE_WAIT_TOP_OF_FRAME
' -------------------------------------------------
' Copy the Backdrop picture to the main chunky buffer screen
' -------------------------------------------------
' AGE_COPY_RECT[CHUNKY_PICTURE,0,0,319,256,CHUNKY_BUFFER,-SCRLLX,0]
' AGE_COPY_RECT[CHUNKY_PICTURE,0,0,319,256,CHUNKY_BUFFER,-SCRLLX+320,0]
AGE_COPY_RECT_QUEUE[QUEUE_POINTER,-SCRLLX,-SCRLLY,BLOCK_COUNT]
AGE_COPY_RECT_QUEUE[QUEUE_POINTER,-SCRLLX+320,-SCRLLY,BLOCK_COUNT]
AGE_COPY_RECT_QUEUE[QUEUE_POINTER,-SCRLLX,-SCRLLY+256,BLOCK_COUNT]
AGE_COPY_RECT_QUEUE[QUEUE_POINTER,-SCRLLX+320,-SCRLLY+256,BLOCK_COUNT]
SCRLLX=(SCRLLX+1) mod 320
SCRLLY=(SCRLLY+1) mod 256
' -------------------------------------------------
' Check for any key presses
' -------------------------------------------------
KEYPRESS$=Inkey$()
If KEYPRESS$=" " Then Exit
Loop
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
End
' ---------------------------------------------------------------
' -----------------------------------------------------------
' -------------->> SUB ROUTINES & FUNCTIONS <<-------------
' -----------------------------------------------------------
' ---------------------------------------------------------------
_CREATE_RECT_QUEUE:
' -------------------------------------------------
' Fill the Copy Rect Queue
' -------------------------------------------------
' This routine makes a queue of 100, 16*16 block
' to be drawn at a target. The target can be offset
' at run time. So you cna make block map.
BLOCKS_WIDE=(320/16)
BLOCKS_HIGH=(256/16)
BLOCK_COUNT=BLOCKS_WIDE*BLOCKS_HIGH
' DIm an array to hold all the queue data in.
' each queue item takes 16 bytes
Dim BLOCKQUEUE((BLOCK_COUNT+1)*16)
QUEUE_POINTER=Varptr(BLOCKQUEUE(0))
' Fill in the queue wwith the copy rects
For LP=0 To BLOCK_COUNT-1
THISBLOCK=Rnd(BLOCK_COUNT-1)
SRCY1=THISBLOCK/BLOCKS_WIDE
SRCX1=THISBLOCK mod BLOCKS_WIDE
SRCX1=SRCX1*16
SRCY1=SRCY1*16
SRCX2=SRCX1+16
SRCY2=SRCY1+16
AGE_SET_RECT_QUEUE[QUEUE_POINTER,LP,CHUNKY_PICTURE,SRCX1,SRCY1,SRCX2,SRCY2,CHUNKY_BUFFER,DEST_XPOS,DEST_YPOS]
DEST_XPOS=DEST_XPOS+16
If DEST_XPOS=>320
DEST_XPOS=0
DEST_YPOS=DEST_YPOS+16
End If
Next
Return
AGE- Star Field / Dot Queue In keeping with the previous demo, here we're another golden oldie, the star field. The demo is drawing 5 layers of 500 pixels (in chunky) over the top of the scrolling picture and the orbiting circles. Yep, it's cut 'n;paste from the same template as most of the other demos are. Each layer of dots is scrolling faster than the previous layer.
To make the star field, we're creating a dot queue for each layer in the scene. This time rather than use Amos arrays for our queue data, were allocated AGE Bank's for each queue. Then storing random dot positions in the queue's via the helper function
AGE_SET_DOT_QUEUE. This function write the coordinate and colour into our allocated buffer. Each dot in the queue costs us 6 bytes, (16bit X, 16bit Y, 16bit Colour). So the size of the dot queue of 50 points is going to use up (50*6)=300 bytes.
Just like the copy rect demo, we're able to render a queue offset from a user defined position. So to make the fields move, we're just bumping a scroll speed variable each layer. Then using that to offset the batch.
Set Buffer 100
' *=-------------------------------------------------------------------=*
'
' AGE - Star Field (DOT QUEUE Example)
'
' By
'
' By Kevin Picone
'
' Last Updated - 31st, Mar, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V072.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / PLANAR AGE screens in Chip Memory
' -----------------------------------
TYPE=AGE_LOWRES+AGE_PLANAR
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
AGE_OPEN_SCREEN[1,320,256,8,TYPE]
CURRENT_BUFFER=0
' -----------------------------------
' CReate Load IFF into this a temp screen.
' -----------------------------------
CHUNKY_BUFFER=3
AGE_OPEN_CHUNKY_SCREEN[CHUNKY_BUFFER,320,256]
' -----------------------------------
' Load IFF into this a temp screen.
' -----------------------------------
CHUNKY_PICTURE=4
FILE$=APPPATH$+"GFXFILES/PICTURES/DRAGONAA_156.IFF"
AGE_OPEN_CHUNKY_SCREEN[CHUNKY_PICTURE,320,256]
AGE_LOAD_IFF_TO_SCREEN[FILE$,CHUNKY_PICTURE]
' copy the palette from the backdrop picture in the chip buffers
AGE_SCREEN_COPY_PALETTE[CHUNKY_PICTURE,0]
AGE_SCREEN_COPY_PALETTE[CHUNKY_PICTURE,1]
' -----------------------------------
' Create standard / simple copper list for viewing our screens.
' -----------------------------------
AGE_CREATE_COPPER[0,0,3,8]
AGE_CREATE_COPPER[1,1,3,8]
' -----------------------------------
' Set copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[1-CURRENT_BUFFER]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
Degree
' -------------------------------------------------
' Init the scene
' -------------------------------------------------
Gosub _CREATE_STAR_FIELDS
AGE_SET_SCREEN[CHUNKY_BUFFER]
Do
' -------------------------------------------------
' Swap Buffers
' -------------------------------------------------
AGE_C2P[CHUNKY_BUFFER,CURRENT_BUFFER]
CURRENT_BUFFER=1-CURRENT_BUFFER
AGE_SET_COPPER[(1-CURRENT_BUFFER)]
AGE_WAIT_TOP_OF_FRAME
' -------------------------------------------------
' Copy the Backdrop picture to the main chunky buffer screen
' -------------------------------------------------
AGE_COPY_RECT[CHUNKY_PICTURE,0,0,319,256,CHUNKY_BUFFER,-SCRLLX,0]
AGE_COPY_RECT[CHUNKY_PICTURE,0,0,319,256,CHUNKY_BUFFER,-SCRLLX+320,0]
SCRLLX=(SCRLLX+1) mod 320
SCRLLY=(SCRLLY+1) mod 256
' -------------------------------------------------
' Render a bunch of orbiting circles
' -------------------------------------------------
RENDER_CIRCLES[160,128,BASEANGLE]
BASEANGLE=(BASEANGLE+1) mod 360
' -------------------------------------------------
' Render Star field
' -------------------------------------------------
Gosub _RENDER_STAR_FIELD
' -------------------------------------------------
' Check for any key presses
' -------------------------------------------------
KEYPRESS$=Inkey$()
If KEYPRESS$=" " Then Exit
Loop
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
End
' ---------------------------------------------------------------
' -----------------------------------------------------------
' -------------->> SUB ROUTINES & FUNCTIONS <<-------------
' -----------------------------------------------------------
' ---------------------------------------------------------------
_CREATE_STAR_FIELDS:
Global ACC
ACC=256
Dim CS(720)
Dim SN(720)
Shared CS()
Shared SN()
INIT_MATH_TABLES[720]
' -------------------------------------------------
' Each Star Field Is a DOT Queue
' -------------------------------------------------
' Number of dots in each layer
STAR_COUNT=500
' Number of star Layers
STAR_LAYERS=5
' Dim array to store the layers SCroll offsets
Dim STAR_SCROLLX(STAR_LAYERS)
' Calc the size of the Star layer in bytes
LAYER_SIZE_IN_BYTES=(STAR_COUNT+1)*6
' Init the star queue (buffers)
For LP=0 To STAR_LAYERS-1
AGE_CREATE_BANK[LP,LAYER_SIZE_IN_BYTES]
AGE_GET_BANK_PTR[LP]
_FILL_QUEUE[Param,STAR_COUNT]
Next
Return
_RENDER_STAR_FIELD:
For LP=0 To STAR_LAYERS-1
AGE_GET_BANK_PTR[LP]
QUEUE_POINTER=Param
If QUEUE_POINTER
X=STAR_SCROLLX(LP)
X=X+(LP+1)
STAR_SCROLLX(LP)=X mod 320
AGE_DOT_QUEUE[QUEUE_POINTER,-X,0,STAR_COUNT]
AGE_DOT_QUEUE[QUEUE_POINTER,-X+320,0,STAR_COUNT]
End If
Next
Return
' ---------------------------------------------------------------
' -----------------------------------------------------------
' >> FILL DOT QUEUE with random dots <<----------
' -----------------------------------------------------------
' ---------------------------------------------------------------
Procedure _FILL_QUEUE[PTR,STARS]
' Fill in the queue with some random pixels
For STARLP=0 To STARS-1
X=Rnd(319)
Y=Rnd(255)
C=Rnd(255)
AGE_SET_DOT_QUEUE[PTR,STARLP,X,Y,C]
Next
End Proc
' ---------------------------------------------------------------
' -----------------------------------------------------------
' >> INIT MATH (COS/SIN) Tables <<----------
' -----------------------------------------------------------
' ---------------------------------------------------------------
Procedure INIT_MATH_TABLES[SIZE]
For LP=0 To SIZE
CS(LP)=Cos(LP)*ACC
SN(LP)=Sin(LP)*ACC
Next
End Proc
' -----------------------------------------------------------------
' -----------------------------------------------------------------
' >> Render Circles <<
' -----------------------------------------------------------------
' -----------------------------------------------------------------
Procedure RENDER_CIRCLES[X,Y,BASEANGLE]
AGE_INK[1]
' -----------------------------------------------------------------
' Draw a bunch of rotating circles in orbit around the screen center
' -----------------------------------------------------------------
For ANGLE=0 To 359 Step 10
ANGLE2=BASEANGLE+ANGLE
X2=CS(ANGLE2)*100
Y2=SN(ANGLE2)*100
X2=X+(X2/ACC)
Y2=Y+(Y2/ACC)
Inc INDEX
AGE_CIRCLEC[X2,Y2,20,INDEX]
Next
End Proc
AGE - Texture Mapped Dragon AGE supports texture mapped triangles, the lib is a lot like PlayBASIC (http://www.playbasic.com) really, just not as complete. The texture mapping works in AGE, but i'm not 100% happy with the rendering code, mainly the edges conversion is a bit dodgy, so the left and right fill convention doesn't seem all that accurate. I'd like to re-write it, and probably will, but better not just now.
Anyway, in this picture you can see the Dragon model (converted from quake MD2 format, into vertex and face lists) spinning in the middle of the screen. It's here we find a few omissions in the scene buffer implementation in AGE. AGE uses a capturing interface where we create a Z buffer cache, then call special functions to buffer our items up in the cache. When we're done, we call the Render scene function, which sorts and renders the scene. This eliminates the need to sort the triangles in AMOS. The issue with the buffer is that it's missing support for texture mapped triangles. So the scene bellow is not actually z buffered.. Will have to fix that in order to make the library more useful.
If you're wondering how fast this stuff is, well it's not express, but of you're only interested in AMOS programming under emulation, then with WinUAE's JIT enabled it's quite fast considering. It'll be interesting seeing what people can knock up with it.
AGE - Line Clipping
As mentioned previously, the library has a lot of meat on the bones in some areas and then in others there's glaring omissions. The line support was another part of the library that I'm not comfortable re-releasing as is. There's a few reasons for this, primarily the existing version of the LINE function only supports rendering to chip memory via Blitter and the clipping isn't stellar. While it works, it's a bit of bottleneck. But there's a problem looming for me, which is time and a complete lack of it for such side projects.
To speed up development of the library and to make extending it more viable in the future, i'm now using a mixture of C and Assembly via VBCC / Phxass. Which just means that in In terms of convenience, I can leverage the code base that PlayBASIC is based upon. So far, i've just been tinkering with it tonight, but i'm already satisfied it's a workable solution. Although was having a few dramas initially.. But the VBCC compiler seems more than happy to produce some decent inner loops, can always inline them if they're not.
One difference to the PB libraries is that AGE is all fixed point integer operations, where PB's is generally floating point with integer inner loops. So rather than drag and drop the line clipper across, found myself having to write an integer version instead... yes... typical.. :) . Anyway, whats interesting is that while I've looked at the older clipper a million times, tonight it dawned on me there's another (pretty obvious) simplification just waiting to be implemented. So with a little messing around, the pure integer version seems to work rather well in the test. Will have to add that in not only to AGE, but PB also...
AGE - Line Render (With Brute Force Clipping) Ok, so last nights little chore (see understatement..), was to drag some of the PB render functions over and make AGE friendly versions. The PB backend is generally C++ (but with C styled render functions) and we're moving to VBCC which is a C compiler, which creates a few syntax issues here and there. But ya get that.
Figured I'd just use VBCC to process the C code to asm, add some macros for our functions and bobs your uncle. But soon run into some problems with compile speed and ultimately collision issues on the assembler side. Had assumed the C compiler would use local labels in the output, but it doesn't seem to, there may well be a switch to turn such a feature on, I dunno.
How i imagined this working, was that I'd just compiling all the C stuff into one blob of assembly, renaming some labels and include. But when compiling the code on the Amiga side, through winUae with -O4 enabled, the process turned out to be pretty time consuming, given it's length. So figured a better (easier/quicker) solution would be to split the C side up into seperate stand alone files. Then compile the parts are needed. This works pretty well speed wise, but we get collisions in the output code from the labels.
To counter the collision hurdle, ended up writing a little app in PlayBASIC to run through and clean up the fragments. So the work flow is drop the function into C, convert that to 68K, clean the output code and include the resulting assembly output into AGE. A bit of messing around, but not too bad, had worse.. :) - Could probably have written the line draw stuff in assembly is less time, but this is just easier all around. Yeah, i'm getting lazy in my old age..
Ok after all that messing around we're now got a Draw Line function that draw to chunky screens. The version of the function you're looking at is brute force clipped (every dot is clipped to the viewport), since i'm yet to drag the clipper across. Had figured all that'd all be done yesterday, but then all the above happened. None the less the routine works pretty well in AGE, when with brute force clipping. This version only draws to chunky screens though, the old blitter based solution is used on planar screens. The trouble with blitter version is there's all this latency between each planar pass. Haven't tested it, but I've sneaking suspicion a cpu filler would be better.
Anyway, here's a bit of scene made from the star field demo with some clipped lines on top of that..
AGE - 8bit Planar Dot Render (Brute Force) After adding the chunky line function, i've been having somewhat of an adventure with dot rendering on planar surfaces. Those who are familiar with planar know the pain for dot rendering to such surfaces. While i've trimmed some fat from the PLANAR DOT rendering routines in AGE, it's certainly not going to be express. But it's supported just in case you absolute have to have it.
The dot plot routine basically is a loop of Bit Sets / Clears across the planes. Rendering to an 8Bit surface, means there's 8 iterations per dot to set the correct colour. Had a play with unrolling the bitsets, which seemed a little quicker, but couldn't justify the bulk of unrolling every colour combination would create. Those you know some AMOS and a little 680x0 assembly knowledge, you could probably allocate a bank and unroll the code into memory yourself then just call it. This approach is commonly found in many old school Amiga demos..
Personally, I'd recommend you avoid Planar screen types altogether and just use CHUNKY screens and C2P the result to the planar display. The performance of this approach under emulation is pretty good with JIT enabled in WinUAE.. I'm guessing those more familiar with AMOS, will be able to squeeze out more performance than me also. None of the examples are compiled in BTW, I'm just running them through the AMOS interpreter, so there's certainly some meat on the bones performance wise.
Anyway, here's the code for the demo. Finally changed backdrop pictures.. :)
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - ANIMATION - PLANAR DOT RENDERING (Brute Force)
'
' By
'
' By Kevin Picone
'
' Last Updated - 9th, Apr, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V074.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / INTERLEAVED AGE screen in Chip Memory '
' -----------------------------------
TYPE=AGE_LOWRES
' TYPE=TYPE+AGE_INTERLEAVED
TYPE=TYPE+AGE_PLANAR
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
AGE_OPEN_SCREEN[1,320,256,8,TYPE]
CURRENT_BUFFER=0
' -----------------------------------
' Load IFF into this a temp screen.
' -----------------------------------
FILE$=APPPATH$+"GFXFILES/PICTURES/TREE.IFF"
AGE_OPEN_SCREEN[3,320,256,8,TYPE]
AGE_LOAD_IFF_TO_SCREEN[FILE$,3]
' copy the palette from the backdrop picture in the chip buffers
AGE_SCREEN_COPY_PALETTE[3,0]
AGE_SCREEN_COPY_PALETTE[3,1]
' -----------------------------------
' Create standard / simple copper list for viewing our screens.
' -----------------------------------
AGE_CREATE_COPPER[0,0,3,8]
AGE_CREATE_COPPER[1,1,3,8]
' -----------------------------------
' Set copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[1-CURRENT_BUFFER]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
' -----------------------------------
' Direct ALL RENDERING To OUR Screen
' -----------------------------------
AGE_SET_SCREEN[CURRENT_BUFFER]
' -----------------------------------
' Load a Font
' -----------------------------------
FONTS$=APPPATH$+"gfxfiles/fonts/"
AGE_LOAD_FONT[FONTS$+"Alex8.font",2]
AGE_SET_FONT[2]
Degree
TIME=Timer
REDRAWS=0
FPS=0
Do
' -------------------------------------------------
' Swap Buffers
' -------------------------------------------------
CURRENT_BUFFER=1-CURRENT_BUFFER
AGE_SET_SCREEN[CURRENT_BUFFER]
AGE_SET_COPPER[(1-CURRENT_BUFFER)]
AGE_WAIT_TOP_OF_FRAME
' -------------------------------------------------
' Copy the temp image to the current render buffer
' -------------------------------------------------
AGE_COPY_RECT[3,0,0,320,256,CURRENT_BUFFER,0,0]
' -------------------------------------------------
' Draw Layer Of Colour Dots to the 8bit planar screen
' -------------------------------------------------
PAD=8
XPOS=(XPOS+1) mod PAD
RENDER_DOT_LAYER[-XPOS,PAD]
COUNT=Param
' ---------------------------
' Render some text on the scene
' ---------------------------
AGE_TEXT["Brute Force PLANAR Dot Rendering",10,10,50]
AGE_TEXT["Dot Count:"+Str$(COUNT),10,20,50]
AGE_TEXT["Fps::"+Str$(FPS),10,30,50]
' calc the fps of this demo
FRAMESPAST=Timer-SECOND_START
RENDER=RENDER+1
If FRAMESPAST=>50
FPS=RENDER
RENDER=0
SECOND_START=Timer
End If
KEYPRESS$=Inkey$()
If KEYPRESS$=" " Then Exit
Loop
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
End
Procedure RENDER_DOT_LAYER[XPOS,PAD]
For YLP=0 To 256 Step PAD
XS=0+XPOS
XE=320+XPOS
For XLP=XS To XE Step PAD
AGE_DOTC[XLP,YLP,XLP]
Next
COUNT=COUNT+(XLP/PAD)
Next
End Proc[COUNT]
NOTE: Not using a a DOT QUEUE in this example
AGE - 8bit Planar Dot Render (QUEUE VERSION) This is basically the same demo, but this one has brute and queued (batching) in it. In queued mode it'll draw about 5000 (8bit) planar points. Building the queue is a little more hasle, but we get rid of lots of Amos function calling overhead by going the extra mile. Even on planar screen, the speed is pretty good running under jitted emulation .
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - ANIMATION - PLANAR DOT RENDERING (Brute Force)
'
' By
'
' By Kevin Picone
'
' Last Updated - 10th, Apr, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V074.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> ALLOC AGE RESOURCE TABLEs <<
'
' *=-----------------------------------------------------------------=*
SCRNS=15
COPS=15
BLKDATAS=10
BANKS=11
FONTS=12
FILECACHESIZE=50000
DCACHESIZE=10000
AGE_ALLOC_RESOURCES[SCRNS,COPS,BLKDATAS,BANKS,FONTS,FILECACHESIZE,DCACHESIZE]
' -----------------------------------
' Create our LOWRES / INTERLEAVED AGE screen in Chip Memory '
' -----------------------------------
TYPE=AGE_LOWRES
' TYPE=TYPE+AGE_INTERLEAVED
TYPE=TYPE+AGE_PLANAR
AGE_OPEN_SCREEN[0,320,256,8,TYPE]
AGE_OPEN_SCREEN[1,320,256,8,TYPE]
CURRENT_BUFFER=0
' -----------------------------------
' Load IFF into this a temp screen.
' -----------------------------------
FILE$=APPPATH$+"GFXFILES/PICTURES/TREE.IFF"
AGE_OPEN_SCREEN[3,320,256,8,TYPE]
AGE_LOAD_IFF_TO_SCREEN[FILE$,3]
' copy the palette from the backdrop picture in the chip buffers
AGE_SCREEN_COPY_PALETTE[3,0]
AGE_SCREEN_COPY_PALETTE[3,1]
' -----------------------------------
' Create standard / simple copper list for viewing our screens.
' -----------------------------------
AGE_CREATE_COPPER[0,0,3,8]
AGE_CREATE_COPPER[1,1,3,8]
' -----------------------------------
' Set copper to view our AGE screen
' -----------------------------------
Doke $DFF096,$180 : Rem Kill Bitplane + copper DMA
AGE_WAIT_TOP_OF_FRAME
AGE_SHOW_COPPER[1-CURRENT_BUFFER]
Doke $DFF096,$8180 : Rem restore Bitplane + copper DMA
' -----------------------------------
' Direct ALL RENDERING To OUR Screen
' -----------------------------------
AGE_SET_SCREEN[CURRENT_BUFFER]
' -----------------------------------
' Load a Font
' -----------------------------------
FONTS$=APPPATH$+"gfxfiles/fonts/"
AGE_LOAD_FONT[FONTS$+"Alex8.font",2]
AGE_SET_FONT[2]
Degree
' CReate a bank to store our queue version
' Init the star queue (buffers)
WIDTH=320
HEIGHT=256
PIXEL_SPACING=4
SIZE=WIDTH*HEIGHT
AGE_CREATE_BANK[1,(SIZE+2)*6]
AGE_GET_BANK_PTR[1]
QUEUE_POINTER=Param
QUEUE_DOT_LAYER[WIDTH,HEIGHT,PIXEL_SPACING,QUEUE_POINTER]
REDRAWS=0
FPS=0
Do
' -------------------------------------------------
' Swap Buffers
' -------------------------------------------------
CURRENT_BUFFER=1-CURRENT_BUFFER
AGE_SET_SCREEN[CURRENT_BUFFER]
AGE_SET_COPPER[(1-CURRENT_BUFFER)]
AGE_WAIT_TOP_OF_FRAME
' -------------------------------------------------
' Copy the temp image to the current render buffer
' -------------------------------------------------
AGE_COPY_RECT[3,0,0,320,256,CURRENT_BUFFER,0,0]
' -------------------------------------------------
' Draw Layer Of Colour Dots to the 8bit planar screen
' -------------------------------------------------
XPOS=(XPOS+1) mod PIXEL_SPACING
If DEMO_MODE=0
RENDER_DOT_LAYER[-XPOS,WIDTH,HEIGHT,PIXEL_SPACING]
COUNT=Param
Else
AGE_DOT_QUEUE[QUEUE_POINTER,-XPOS,0,COUNT]
End If
' ---------------------------
' Render some text on the scene
' ---------------------------
If DEMO_MODE=0
AGE_TEXT["8Bit Planar Dot Rendering (Brute Force)",10,10,50]
End If
If DEMO_MODE=1
AGE_TEXT["8Bit Planar Dot Rendering (Queue)",10,10,50]
End If
AGE_TEXT["Dot Count:"+Str$(COUNT),10,20,50]
AGE_TEXT["Fps::"+Str$(FPS),10,30,50]
' calc the fps of this demo
FRAMESPAST=Timer-SECOND_START
RENDER=RENDER+1
If FRAMESPAST=>50
FPS=RENDER
RENDER=0
SECOND_START=Timer
End If
KEYPRESS$=Inkey$()
If KEYPRESS$="m"
DEMO_MODE=1-DEMO_MODE
End If
If KEYPRESS$=" " Then Exit
Loop
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
End
Procedure RENDER_DOT_LAYER[XPOS,WIDTH,HEIGHT,PAD]
For YLP=0 To HEIGHT Step PAD
XS=0+XPOS
XE=WIDTH+XPOS
For XLP=XS To XE Step PAD
AGE_DOTC[XLP,YLP,INDEX]
Inc INDEX
Next
COUNT=COUNT+(XLP/PAD)
Next
End Proc[COUNT]
Procedure QUEUE_DOT_LAYER[WIDTH,HEIGHT,PAD,PTR]
For YLP=0 To HEIGHT Step PAD
For XLP=0 To WIDTH Step PAD
C=XLP
AGE_SET_DOT_QUEUE[PTR,STARLP,XLP,YLP,INDEX]
STARLP=STARLP+1
Inc INDEX
Next
COUNT=COUNT+(XLP/PAD)
Next
End Proc[COUNT]
AGE - Remap BOX (Colour Remapping) The AGE_REMAP_BOX function allows us to remap a rectangle of chunky pixels against a remap table of our choice. To make the picture bellow, i'm drawing a bunch of 16 * 16 rects onto the chunky buffer at random positions. Each rect is using a table that adds 2 to each colour index, where the colours are clamped at 255. At the end of the frame, i'm subtracting one from every index.
So if a pixel is drawn say 5 times, then after this it's value will be 10. The palette is set up so that colour index 0 is the backdrop coluor, where the entire 256 colour palette fades towards the brighter colour. Since we're only subtracting one from each pixel each frame, the pixels appear to linger and then slowly fade out or cool down.
i must ask,why are you doing this age project?
I loved the Amiga but why?...
There's plenty of reasons, but the one's that sparked my interest the most would be the release of Windows packaged version of AMOS. This installer allows basic programmers run
AMOS on Windows PC (via emulation of course) legally. AGE
isn't new, it's much older than PlayBASIC (http://www.playbasic.com). All i'm doing here, is cleaning up the library (to a degree) in order make it more useful for those intersted in AGA programming under AMOS emulation.
The rather interesting by product of using emulation like this, is that programmers could knock up little games/demos in AMOS then distribute them across various platforms, the same way AMOS is being distributed above.. Which is rather bizarre, but perfectly viable.
Hello Kevin.
Just registered to say that I (and many other amos users) have been following your progress on this for a couple of weeks now.
I must say that it is looking promising. I use a real Amiga for AMOS programming and there are many others like me who still
design programs for the Amiga.
I really hope that you can knock up an AGA Dual Playfield mode at some point. I've tried it myself
using a modified copper list but its not a workable solution. I have however, managed to get a 'Sliced-HAM' screen working
using the copper list from a 4 bit display. It displays 16 unique colours on each scan line so on a PAL display you have 4096 colours
without the dithering that you get on a standard HAM display. If you want the code for AGE then I would be more than happy
to give you it so that you can include it in AGE.
Keep up the good work.
Kev G.
Hi Kev,
Quote
Just registered to say that I (and many other amos users) have been following your progress on this for a couple of weeks now.
I must say that it is looking promising. I use a real Amiga for AMOS programming and there are many others like me who still
design programs for the Amiga.
Well, it's nice to know that somebody noticed, had assumed so from the view count. I really can't stress enough that while AGE works, its far from a tried and true polished solution, so people should keep their expectations well and truly in check. I hope it works OK on real hardware, but it might not also !
The clean up has taken a bit longer than expected, but will not doubt reuse bits of the lib in other projects.. so all is not lost.
Quote
I really hope that you can knock up an AGA Dual Playfield mode at some point. I've tried it myself
using a modified copper list but its not a workable solution. I have however, managed to get a 'Sliced-HAM' screen working
using the copper list from a 4 bit display. It displays 16 unique colours on each scan line so on a PAL display you have 4096 colours
without the dithering that you get on a standard HAM display. If you want the code for AGE then I would be more than happy
to give you it so that you can include it in AGE.
yeah.. Dual playfield & dyanmic had crossed my mind, the copper support in the library isn't like AMOS's native management, in fact there's barely any copper related functions at all. The standard view, just sets the display mode, bitplane pointers, 24bit palette and that's about it. You can roll your own copper list, which is not unlike how the original AmosAGA hack works.
Setting a dual playfield screen, will mean creating two 4bit AGE screens, then building a copper view with dual mode enabled. One of the issues with the
AGA chipset, is that running all 8 bitplanes chews up a loads of DMA during our video refresh. Much, like turning hires modes on. We can reduce this some what, by enabling 32bit or 64bit fetch modes for the video hardware, but this some negative side affects, in that it means everything must be alligned to either 32 or 64 bits. This is not really issue if you want to scroll the screen vertically, but horizontally it can be rather painful, since we have to over side the buffers to accommodate hardware scrolling, which kills most of the hardware sprites.
Anyway, we'll see how we go.
AGE - 8Bit Planar Line Rendering / Line Queues There's still a few odds and ends that i'm cleaning up. The replacement line clipper and chunky line render are in and work pretty well. But the older line render was blitter based and choked badly, very badly. It didn't really fit with design of library, which was originally written to favor CPU rendering over blitter, as mid range systems 020/030 with fast memory can easy beat it.
Anyway, so now the line function can draw to chunky or planar surfaces, if your going to be drawing to planar, then I'd really recommend going easy on it, in particular when rendering directly to chip/video memory. Speed wise, it's ok given its a generic routine after all. Moreover, while looking through the functions there was
line queue stub, but no actual routine. I dunno if that was in the older release version or not, I think this based on the final source(s), but ya never know.. But it's added now.
The Line queue has two functions the render function AGE_LINE_QUEUE[Ptr,Xoffset,YOffset,FLAGS,ITEMCOUNT] and the queue builder function. AGE_SET_LINE_QUEUE[Ptr,QueueIndex,X1,Y1,X2,y2,ColorINdex] , each queye item is 10 bytes in memory (X1.w,Y1.w,X2.w,y2.w,Colour.w) . When you render, you can uses the flags parameter to select if you want the output to be clipped or not. Warning, if you turn clipping off and render outside the viewport, it will crash !
AGE - Interleaved Planar + Porting Colour Functions
The original AGE lib had provision for both standard PLANAR and INTERLEAVED planar, but the interleaved mode didn't seem to work in the latest versions. Turned out to be just the pre mult table wasn't being set up correctly in that mode. The premult's is a look up table of Y values, that library routines use when working out the address of particular scan line when reading or writing a screen buffer, it's just quicker fetching pre-computed values than multing the Y coordinate by the surface pitch every time.
In early versions of the update the Colour functions were written in AMOS, but unfortunately doing things like blending RGB values is a lot of work for AMOS to actually do. Wasn't going to bother, but if you try and fade the palette IN/OUT then just calling the blend function 256 times can eat most of a complete frame on it's own. Which is a bit scary really, so those functions have been ported to assembly and dropped into the library.
For the sake of a comparison, the native version the RGB_ALPHA_BLEND function is about 25 FRAMES (that's about 25*20 milliseconds) faster than interpreted AMOS implementation when blending 2000 colours. While not exactly a fair comparison, it does demostrate just how important data management seems to be in AMOS.
Another subtle change has been to the initialize function for AGE, it appears that I can use variable pointers to help with the function pointer initializations. While I haven't rolled this completely out, it'd not doubt save some code bloat in the library, with minimal fuss. The down side of such a change is the having to be a bit more careful with the order of declaration in the start up.
Sample Colour Functions Test Code (Requires Dev Version Of AGE).
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - Colour Functions
'
' By
'
' By Kevin Picone
'
' Last Updated - 13th, Apr, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V076.AMOS"
' *=-----------------------------------------------------------------=* '
'
' >> TEST COLOUR FUNCTIONS <<
'
' *=-----------------------------------------------------------------=*
RGB[255,16,$A0]
C=Param
Print Hex$(C)
RGBR[C]
Print "R:"+Hex$(Param)
RGBG[C]
Print "G:"+Hex$(Param)
RGBB[C]
Print "B:"+Hex$(Param)
'-----------------------------------------------
Print ""
RGB_24TO12[C]
C12=Param
Print "RGB12to12:"+Hex$(C12)
RGB_12TO24[C12]
C24=Param
Print "RGB12to24:"+Hex$(C24)
'-----------------------------------------------
RGB1=$8090A0
RGB2=$10203
RGB_ADD[RGB1,RGB2]
C=Param
Print ""
Print "RGB Alpha Add"
Print Hex$(RGB1)
Print Hex$(RGB2)
Print Hex$(C)
RGB_SUB[RGB1,RGB2]
C=Param
Print "RGB Alpha Add"
Print Hex$(RGB1)
Print Hex$(RGB2)
Print Hex$(C)
'-----------------------------------------------
Print ""
Print "FADE RGB"
RGB_FADE[RGB1,0.5]
C=Param
Print Hex$(RGB1)
Print Hex$(C)
'-----------------------------------------------
Print "Press Space"
Wait Key
Cls
Print ""
Print "FADE ALPHA BLEND"
RGB1=$AABBCC
RGB2=$334455
RGB_ALPHA_BLEND[RGB1,RGB2,0]
Print Hex$(Param)
RGB_ALPHA_BLEND[RGB1,RGB2,1]
Print Hex$(Param)
RGB_ALPHA_BLEND2[RGB1,RGB2,1]
Print Hex$(Param)
RGB_ALPHA_BLEND[RGB1,RGB2,0.5]
Print Hex$(Param)
RGB_ALPHA_BLEND2[RGB1,RGB2,0.5]
Print Hex$(Param)
Print "Speed Test Start"
M=10000
ST=Timer()
For LP=0 To M
RGB_ALPHA_BLEND[RGB1,RGB2,0.5]
Next
T=Timer()
Print(T-ST)
ST=Timer()
For LP=0 To M
RGB_INT_ALPHA_BLEND[RGB1,RGB2,128]
Next
T=Timer()
Print(T-ST)
ST=Timer()
For LP=0 To M
RGB_ALPHA_BLEND2[RGB1,RGB2,0.5]
Next
T=Timer()
Print(T-ST)
Wait Key
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
AGE - Convex Polygon Rendering (Flat / Gouraud / Texture Mapped) Dropped a bit more time into this update yesterday afternoon, the new code is a replacement of poylgon edge conversion routines. The code was basically drag and dropped in from PlayBASIC (http://www.playbasic.com), while the library already contained triangle based rendering routines, which apart from being a big mess, they're limited to only triangles. So of you want to render a textured quad, you had to draw it in at least two halves. When you do this, we're doubling a number operations not to mention that one edge is converted twice.
So a better solution is to use a polygon filler than can render sets of 3 or more vertex, which is how the replacement routine works. It's limited to the 32 vertex
, but can potentially draw any set as long as the vertex form a convex polygon shape. It'll fail on the concave or complex polygons.
In the picture bellow we're looking at a flat filled quad drawn over the star field example, the colours per scan line is just random junk in this example. Porting the code was pretty painless, a few syntax issues with comments in VBCC, but you get that. Typically when things are moving quickly something pops up to hinder that progress and this time was no exception. So the routine was ported, but of course when I called it from the library, nothing happened..
Long story short, the ported code isn't identical to the version in PB, this version is styled to use the AGE screen structure. In AGE the viewport structure is 16bit, it's 32bit in PB. Which turned out to the problem. The caller was passing a 32bit structure in where it expected a 16 bit. Making it reject virtually anything. Pretty novel issue, but annoying none the less.
The polygon fillers, don't actually draw pixels. It just calcs the visible spans. In the example bellow, i'm just running through the resulting span buffer can drawing LINES between them for test purposes. What i plan to do in this session, is set up the filler to use the built in SPAN routines (which are used in Circles/Boxes) to render the strips out. At least then the flat shaded filler work on chunky or planar/interleaved screens. Texture Mapping and Gouraud will be CHUNKY only i'm afraid.
AGE - Filled TRI + QUADS Dropped in the some commands into the Amos wrapper (Second picture), they're basically the same as the PB commands, so we've
AGE_TRI[x1,y1,x2,y2,x3,y3] and it's sister function
AGE_TRIC[x1,y1,x2,y2,x3,y3,Colour] as well as
AGE_QUADC[x1,y1,x2,y2,x3,y3],x4,y4,Colour. It's nice being able to project some points and and just draw quad out of the edge verts.
The Texture mapped and gouraud version of the span buffering as in, but there's no AMOS wrapping code at the moment. There's a lot of Amos function overhead passing all the required fields into the function. Might end up having Textured TRI + Textured Quad functions, with some type of user generated vertex buffer. A vert buffer would prolly be best.
AGE - FIXED POINT MATH / TRIG FUNCTIONS
From messing with AMOS, you can't help but notice floating point performance isn't pretty. It's not really AMOS's fault, given it's just using the Amiga floating point math libraries underneath, which need to emulate FPU when one's not present. You can improve the performance on real hardware, if you have FPU in your system, by replacing the math lib with an FPU optimized version (Check Aminet there some on there). Even so, Fixed Point should still be better.
While most of the examples shown here are using fixed point, there is some floating poijnt usage still in them, namely COS/SIN functions. So i've knocked up a couple of Fixed point replacement functions for the native routines. The routines use a 16:16 formatted fixed point values, so there's 16 bits one whole part and 16 bit fractional part. This limits the numeric range, but we can perform floating point styled using Integer operations without same the Floating Point overhead.
The functions i've included focus around cos/sine, where functions like AGE_COS[ANGLE] / AGE_SIN[ANGLE] are the COS/SIN equivalents. Internally the lib uses a sinus TABLE, so it should be pretty efficient. I often use polar coordinates when mapping character paths in games (Angle and Speed), so i've added a couple of functions that bundle up some processing into a single function. While i suspect this will be slower from the AMOS interpreter, compiled it should work really well, if not... You could actually inline some of those function if push came to shove.
Anyway, in the example we're plotting some circles using the functions.
Set Buffer 50
' *=-------------------------------------------------------------------=*
'
' AGE - FIXED POINT MATH/ TRIG FUNCTIONS
'
' By
'
' By Kevin Picone
'
' Last Updated - 18th, Apr, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V081.AMOS"
' *=-----------------------------------------------------------------=* '
'
' >> TEST FIXED POINT MATH FUNCTIONS <<
'
' *=-----------------------------------------------------------------=*
'
' Step Fixde point accuracy (16 bits if fraction part)
ACC=$10000
' Size of the circles we'll be drawing
RADIUS=100
' Testing the FIXED POINT COS + SIN
' These function return a cos/sin value in fixed point 16:16 format
' the function returns results in fixed point 16:16 format
For LP=-360 To 720 Step 2
AGE_COS[LP]
X=Param*RADIUS
AGE_SIN[LP]
Y=Param*RADIUS
Plot 160+X/ACC,100+Y/ACC
Next
Print "AGE FIXED POINT COS & SIN"
Print "Ppess Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT COSRADIUS + SINRADIUS
' This function Mults the Cos/Sin value by radius as part of it
' the function returns results in fixed point 16:16 format
For LP=-360 To 720 Step 2
AGE_COSRADIUS[LP,RADIUS]
X=Param
AGE_SINRADIUS[LP,RADIUS]
Y=Param
Plot 160+X/ACC,100+Y/ACC
Next
Print "AGE FIXED POINT COSRADIUS & SINRADIUS"
Print "Press Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are in fixed point 16:16 format
For LP=-360 To 720 Step 2
AGE_POLAR[LP,RADIUS]
X=Dreg(0)
Y=Dreg(1)
Plot 160+X/ACC,100+Y/ACC
Next
Print "AGE POLAR"
Print "Press Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR STEP
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are in fixed point 16:16 format
' calc the screen center in Fixed point
CX=160*ACC
CY=100*ACC
For LP=-360 To 720 Step 2
AGE_POLARSTEP[LP,RADIUS,CX,CY]
X=Dreg(0)
Y=Dreg(1)
Plot X/ACC,Y/ACC
Next
Print "AGE POLAR STEP (FIXED POINT)"
Print "Press Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR STEP (INTEGER)
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are as signed integers
' calc the screen center in Fixed point
CX=160*ACC
CY=100*ACC
For LP=-360 To 720 Step 2
AGE_INTPOLARSTEP[LP,RADIUS,CX,CY]
X=Dreg(0)
Y=Dreg(1)
Plot X,Y
Next
Print "AGE POLAR STEP (INTEGER)"
Print "Press Space"
Wait Key
Cls
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
AGE - FIXED POINT MATH / ROTATE2D and ROTATE2D BATCH
Did a little more tinkering with the math functions last night, adding a 2D ROTATE vertex function, along with a Batch version of the function. The rotated 2d function, takes an individual 2D vector and rotates this by the required number of degrees AGE_ROTATE2D[ANGLE,X,Y], the function returns the rotated vector in registers D0 and D1.
So to rotate the point at 100x,200y by 50 degrees we'd go
AGE_ROTATE2D[50,100,200]
NewX = Dreg(0)
NewY = Dreg(1)
Input and returns coordinates are in 32bit Integers. Internally the rotation is all fixed point though and is faster than manually rotating the point in pure AMOS code. The trouble is with calling AMOS functions heavily in our programs, is that it add overhead to the procedure. So a faster method, is to rotate a BATCH of vertex in one hit. So the function call has very little (none really) impact upon performance. To do this, we've added the AGE_ROTATE2D_BATCH function.
AGE_ROTATE2D_BATCH is a little more complex to set up, but will give us much better through put for the more verts you want to rotate. The function expects the user to set up two buffers of suitable size. ( if they're not it'll die !). These are the SOURCE and DESTINATION vertex buffers. It's not recommended to use the same buffer for both source and destination, since this will only give you compounded precision errors, over successive rotations.
AGE_ROTATE2D_BATCH[SRCPTR,SRCVERTEXMODULO,DESTPTR,DESTVERTEXMODULO,METHOD,ANGLE,VERTEXCOUNT]
SrcPTR = The address of the original (none rotated) vertex
SrcVertexModulo = The distance (in bytes) between each vertex
DESTPTR = The address where the rotated vertex will be stored.
DestVertexModulo = The distance (in bytes) between each vertex
METHOD = 1= 32bit Vertex , - = 16bit vertex
ANGLE = To rotate this set i degrees
VERTEXCOUNT = Number of verts in this batch
When calling the function, we can choose the size of the vertex data using the METHOD field. There's only 2 options, 16bit or 32bit. In 16bit mode, the routine expects the X data to be located at SRCPTR, and Y data to be located at SRCPTR+2, same for Destination data. In 32bit mode, they're 4 bytes apart in source and destination. The modulo allows you to access structures of different width.
Ideally what this allows us to do, is create queues of dots / lines then batch rotate the ordinates prior to rendering the queue. This bypasses a huge amount of AMOS overhead and will give us near assembly results.
Math Test Example
' *=-------------------------------------------------------------------=*
'
' AGE - FIXED POINT MATH/ TRIG FUNCTIONS
'
' By
'
' By Kevin Picone
'
' Last Updated - 19th, Apr, 2012
'
' (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
'
' www.UnderwareDesign.com
'
' *=-------------------------------------------------------------------=*
'
' Sorry but AMOSPRO seems to require absolute include paths ??
' SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
' THE DEMOS FROM AMOS/AMOSPRO correctly on your machine
' To make the pathing less annoying, here we store the 'root path'
' in a variable APPPATH$ .. Then use this through our program.
APPPATH$="Dh0:/AGE_V102/"
' Set the location of the AGE lib..
AGE_LIBRARY_PATH$=APPPATH$+"Includes/Asm/Age.lib"
' Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V082.AMOS"
' *=-----------------------------------------------------------------=*
'
' >> TEST FIXED POINT MATH FUNCTIONS <<
'
' *=-----------------------------------------------------------------=*
'
Curs Off
' Step Fixed point accuracy (16 bits if fraction part)
ACC=$10000
' Size of the circles we'll be drawing
RADIUS=100
' Testing the FIXED POINT COS + SIN
' These function return a cos/sin value in fixed point 16:16 format
' the function returns results in fixed point 16:16 format
For LP=-360 To 720 Step 2
AGE_COS[LP]
X=Param*RADIUS
AGE_SIN[LP]
Y=Param*RADIUS
Plot 160+X/ACC,100+Y/ACC
Next
Print "AGE FIXED POINT COS & SIN"
Print "Ppess Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT COSRADIUS + SINRADIUS
' This function Mults the Cos/Sin value by radius as part of it
' the function returns results in fixed point 16:16 format
For LP=-360 To 720 Step 2
AGE_COSRADIUS[LP,RADIUS]
X=Param
AGE_SINRADIUS[LP,RADIUS]
Y=Param
Plot 160+X/ACC,100+Y/ACC
Next
Print "AGE FIXED POINT COSRADIUS & SINRADIUS"
Print "Press Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are in fixed point 16:16 format
For LP=-360 To 720 Step 2
AGE_POLAR[LP,RADIUS]
X=Dreg(0)
Y=Dreg(1)
Plot 160+X/ACC,100+Y/ACC
Next
Print "AGE POLAR"
Print "Press Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR STEP
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are in fixed point 16:16 format
' calc the screen center in Fixed point
CX=160*ACC
CY=100*ACC
For LP=-360 To 720 Step 2
AGE_POLARSTEP[LP,RADIUS,CX,CY]
X=Dreg(0)
Y=Dreg(1)
Plot X/ACC,Y/ACC
Next
Print "AGE POLAR STEP (FIXED POINT)"
Print "Press Space"
Wait Key
Cls
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR STEP (INTEGER)
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are as signed integers
' calc the screen center in Fixed point
CX=160*ACC
CY=100*ACC
For LP=-360 To 720 Step 2
AGE_INTPOLARSTEP[LP,RADIUS,CX,CY]
X=Dreg(0)
Y=Dreg(1)
Plot X,Y
Next
Print "AGE POLAR STEP (INTEGER)"
Print "Press Space"
Wait Key
Cls
Screen Open 0,320,200,16,Lowres
Screen Open 1,320,200,16,Lowres
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing the FIXED POINT POLAR STEP (INTEGER)
' This function returns movement along X / Y cord
' from an angle and Radius/speed
' the results are as signed integers
' calc the screen center
CX=160
CY=100
NUMBEROFLOOPS=50
For LP=0 To NUMBEROFLOOPS
CURRENTBUFFER=1-CURRENTBUFFER
Screen 1-CURRENTBUFFER
Screen Show CURRENTBUFFER
If LP+1=NUMBEROFLOOPS
Print "Press Space"
End If
Cls
Print "AGE ROTATE 2D"
ANGLE=ANGLE+5 mod 360
AGE_ROTATE2D[ANGLE,0,0]
X1=CX+Dreg(0)
Y1=CY+Dreg(1)
AGE_ROTATE2D[ANGLE,100,0]
X2=CX+Dreg(0)
Y2=CY+Dreg(1)
AGE_ROTATE2D[ANGLE,100,100]
X3=CX+Dreg(0)
Y3=CY+Dreg(1)
AGE_ROTATE2D[ANGLE,0,100]
X4=CX+Dreg(0)
Y4=CY+Dreg(1)
Polyline X1,Y1 To X2,Y2 To X2,Y2 To X3,Y3
Polyline X3,Y3 To X4,Y4 To X4,Y4 To X1,Y1
Next
Print "Press Space"
Wait Key
' ------------------------------------------------------
' ------------------------------------------------------
' ------------------------------------------------------
' Testing BATCH ROTATE Function on array of 32bit integers
' the function has two data type methods built in. It can
' rotate batches of 16bit vertexs or 32bit.. First we'll test
' 32bits
' I'm using two arrays here. One as the source Vertex buffer
' and the other is the ROTATED vertex buffer. SO we create our
' vertex set. Then we just rotate them during the game, thus
' avoiding the need to recreate the source vertex each time.
'
' You should be able to use this function with the various queue
' functions in the library.
VERTEXCOUNT=100
' The number of bytes between each vertex in the source structure
SRCVERTEXMODULO=8
' The number of bytes between each vertex in the source structure
DESTVERTEXMODULO=8
Dim VERTBUFFER(VERTEXCOUNT*(SRCVERTEXMODULO/4))
Dim ROTATED_VERTBUFFER(VERTEXCOUNT*(DESTVERTEXMODULO/4))
INDEX=0
For LP=0 To(VERTEXCOUNT-1)
X1=Rnd(320)-160
Y1=Rnd(200)-100
VERTBUFFER(INDEX)=X1
VERTBUFFER(INDEX+1)=Y1
Add INDEX,2
Next
' calc the screen center
CX=160
CY=100
SRCPTR=Varptr(VERTBUFFER(0))
DESTPTR=Varptr(ROTATED_VERTBUFFER(0))
NUMBEROFLOOPS=25
For LP=0 To NUMBEROFLOOPS
Screen Show CURRENTBUFFER
CURRENTBUFFER=1-CURRENTBUFFER
Screen CURRENTBUFFER
Cls
Print "AGE ROTATE 2D BATCHES"
If LP+1=NUMBEROFLOOPS
Print "Press Space"
End If
ANGLE=ANGLE+1 mod 360
AGE_ROTATE2D_BATCH[SRCPTR,SRCVERTEXMODULO,DESTPTR,DESTVERTEXMODULO,1,ANGLE,VERTEXCOUNT]
INDEX=0
X1=CX+ROTATED_VERTBUFFER(INDEX)
Y1=CY+ROTATED_VERTBUFFER(INDEX+1)
For EDGELP=1 To VERTEXCOUNT-1
X2=CX+ROTATED_VERTBUFFER(INDEX)
Y2=CY+ROTATED_VERTBUFFER(INDEX+1)
Add INDEX,2
Polyline X1,Y1 To X2,Y2
X1=X2
Y1=Y2
Next
Next
Print "Press Space"
Wait Key
' -------------------------------------------------------------
' -------------------------------------------------------------
' ------------------>> BRUTE FORCE TEST <<---------------------
' -------------------------------------------------------------
' -------------------------------------------------------------
Screen CURRENTBUFFER
Screen To Front CURRENTBUFFER
Cls
Print "Brute Force Math Test"
COUNT=10000
_STARTTIME=Timer
For LP=0 To COUNT
X=Cos(ANGLE)
Next
Print "Floating Point COS:"+Str$(Timer-_STARTTIME)
_STARTTIME=Timer
For LP=0 To COUNT
AGE_COS[ANGLE]
X=Param
Next
Print "Fixed Point COS:"+Str$(Timer-_STARTTIME)
_STARTTIME=Timer
For LP=0 To COUNT
X=Cos(ANGLE)*RADIUS
Next
Print "Floating Point COS* RADIUS:"+Str$(Timer-_STARTTIME)
_STARTTIME=Timer
For LP=0 To COUNT
AGE_COSRADIUS[ANGLE,RADIUS]
X=Param
Next
Print "Fixed Point COSRADIUS:"+Str$(Timer-_STARTTIME)
_STARTTIME=Timer
For LP=0 To COUNT
Dreg(0)=ANGLE
Dreg(1)=RADIUS
Call LIBAGE_COSRADIUS
X=Dreg(0)
Next
Print "Unrolled Fixed Point COSRADIUS:"+Str$(Timer-_STARTTIME)
Wait Key
' -----------------------------------
' Clean Up/Close Down AGE
' -----------------------------------
AGE_CLEAN_UP
At the bottom of the test is a loop that runs some brute force performance comparisons on the AGE_COS/SIN functions compared to the native floating point functions. From the emulator I get some interesting, but not that unexpected results. If we compare COS() with AGE_COS[], over 10,000 calls, the AGE function is quicker, but not dramatically so. A lot benefit is lost wrapping the function as a Procedure. Which is demonstrated nicely when comparing the Cos(Angle)*Radius equivalents, in that they're about the same speed here. That is, until you get rid of the procedure, then it's twice as fast.
Compiling Amos Issues
So far i'm just running the demos from the AmosPRO IDE / runtime interpreter, so we should be able to strip out a lot of runtime overhead when compiled to EXE, but the compiler doesn't want to play nice. Not too sure what it's problem is, but it appears that the AGE Wrapper might need to be modded in order to be able to compile the final game/demos to EXE's. Which is really NOT what i was hoping. The library does actually run really well from the WinAUE 2.3.3 / with JIT enabled. In fact we're seeing demo's approach 50fps under emulation, chunky or planar doesn't seem to matter. Which is neat for those running under emulation, but compiling to exe would be a huge benefit on real hardware.
AGE - DRAW POLY / DRAW TEXTURED POLY These touch back to triangle / quad routines mentioned previously. In the original library, it seems that AMOS would spit out an integer overflow if it felt the result exceeds the range of 32bit value in some operations, which i'd never noticed before. Anyway this would cause issues if which the polygon routines try and bundles up the coordinates into packed registers.
For example, the in triangle function there's enough registers to happily just send them as is, but if you want gouraud or texture mapping you need to send more information than just the vertexs. So the function would pack pairs X1,Y1 / X2,Y2 / X3,Y3 into three 32bit registers.
A bit like this.
PackedX1Y1 = (X1 * $10000) + Y1
But there's a few obvious problems with this, but mainly since the X1/Y1 are 32 bit integers, what happens if X1 or Y1's negative ? .. Yeah it overflows... To Get around this we need to mask the fields before ,merging the bits.
Something like this,
PackedX1Y1 = ((X1 and $ffff) * $10000) + (Y1 and $ffff)
But you'll still get overflows in AMOS, not too sure how MULT is implemented in AMOS actually, since the 68000 cpu doesn't have a native 32bit integer multiply, which makes you wonder ? hmmm. Of course shifting is a much better option, but it seems the shifters are a type of custom operator in Amos.
So to pack a pair of fields, we've effectively forced to do this.
X1 = X1 and $ffff
Rol.l 16,X1
PackedX1Y1 = X1 or (Y1 and $ffff)
Now i only bring it up, as that's a lot of overhead on the AMOS side of the library to batch up the data every time to send it. Obviously, it'd be a much better idea to stream line the data setup into a more Amos friendly format like an array or memory bank.
So the DRAWPOLY functions come at the same problem from that perspective, basically we fill in a list of Vertex data, pass this list to the polygon rendering function and it draws it for us (if possible). There's a few limitations, such as the shape must be convex and less than 32 vertex in the list, but that's about it. You can draw filled shapes and texture mapped shapes also.
The DrawPoly functions expect user to lay the vertex data out in the following 20 byte structure, X,Y, U,V, Col. So each field is a 32bit integer
0 X
4 Y
8 U
12 V
16 Col
Size = 20 bytes
So if you wanted to create a vertex buffer in an array, what you'd is dimension the array so there's 5 times the number vertex you need. Why 5 times ?, well each cell in the array is 4 bytes (one 32bit integer) so each cell is a field in our vertex structure above, since the structure is 20 bytes, we'll need 5 slots per vertex in our array .
Ie.
VertexCount = 10
Dim Vertex_Buffer(VertexCount * 5)
Then to render a textured 10 sided poylgon disc thing.. We can do that like this.
' Array index into Vertex_Buffer()
INDEX=0
' Step in degrees for this number of vertex
ANGLESTEP=360/VERTEXCOUNT
' Bump rotation angle each refresh
SPIN=SPIN+2 mod 360
' Set starting angle to the current rotation angle
ANGLE=SPIN
' Angle Texture coordinates. These aren't rotating
ANGLE2=0
For LP=0 To VERTEXCOUNT-1
' bump the current angle
ANGLE=ANGLE+ANGLESTEP mod 360
' project a polar cord at 150 units same as X=Cos(Angle)*Radius / Y=Sin(angle)*RAdius
AGE_POLAR[ANGLE,150]
' set the X + Y cords of the Vertex
VERTEX_BUFFER(INDEX)=160+Dreg(0)/$10000
VERTEX_BUFFER(INDEX+1)=128+Dreg(1)/$10000
' set the U/V cord
ANGLE2=ANGLE2+ANGLESTEP
AGE_POLAR[ANGLE2,124]
VERTEX_BUFFER(INDEX+2)=128+Dreg(0)/$10000
VERTEX_BUFFER(INDEX+3)=128+Dreg(1)/$10000
' bump the array index to the next vertex in buffer
Add INDEX,5
Next
' Get the address of the first byte in this array
PTR=Varptr(VERTEX_BUFFER(0))
' draw this shape as textured polygon using the dragon texture
AGE_DRAWTEXTUREDPOLY[PTR,VERTEXCOUNT,DRAGON_TEXTURE]
Bellow you can see the result of the code, which is it's drawing a spining textured circle shape thing using the dragons texture map for something to look at. You can draw the same thing as triangles, which is not a lot of extra programming, but it's lot of extra work on the AMOS and ultimately AGE.
AGE - GOURAUD TORUS (AGAIN) Hadn't updated all the polygon filler routines to the N-sided versions, so bellow (Second shot) we see the gouraud torus demo, using the new filler with a object pushed right up in the viewers face. It's running in the low
30fps mark under emulation (with jit). To be honest, the fill quality isn't great, but it works.
AGE - GOURAUD QUAD Dropped a AGE_GouraudQUAD[x1,y1,c1,x2,y2,c2,x3,y3,c3,x4,y4,c4] function into the wrapper. Pictured bellow drawing a quad between some random palette data.
A.G.E V1.02 BETA #1 is Now Available (21st, Apr, 2012)
This release contains an 'as is' snap shot of the AGE package at this time. Those familiar with the original package will notice a lot has changed since the previous release some 12 years ago, way too much to paraphrase now. So to get up to speed please make sure you
read this thread and the
examples carefully.
The package includes revision 85 of AGE AMOS wrapper and binary library, as well as various examples.
What's AGE ? it's a replacement / plug in graphics engine for AMOSPRO that enables AMOS programmers to use the AGA chipset.
You can find out more information about AGE at AGE HOME PAGE (http://www.underwaredesign.com/?page=programs.A-G-E-)
Download Download AGE V1.02 BETA #1 (http://www.underwaredesign.com/getfile.php?file=Get-AGE-Beta/AGE-V102-Beta-01.zip)
Installation Download the package to your computer and unzip the folder. The examples are hard coded to expect a path of
DH0:AGE-V102-Beta-01, so you'll need to mod the paths if you place it anywhere else. You don't need to the copy the AGE.LIB file into your libraries folder, it's not a general purpose library.
History Changes since last release
---------------------------------------------------------------------------------------------------------------
------------------------------------>> Release V1.02 - BETA #1 << -------------------------------------------------
---------------------------------------------------------------------------------------------------------------
Too many to mention
Hi all,
First to all I want to say CONGRATULATIONS!! Kevin Picone for make this AGE extension Amazing Work!
I Coding in Amos/Amos pro from early 90 until 2003 and now in 2012 I working again with Amos in some own projects an example : http://youtu.be/qv8IK6aXV8k or http://youtu.be/v-0_gJQAHDM this only some examples about ideas I want to do in future visit my web site in www.amiten.webatu.com for more info.
The thing is I would like to use your Extension to Have AGA support in AMOS ( just a Dream if I can Do it)
At the moment I only play i little bit with your extension AGE , but cant do work.
Y download the last Beta calls Download AGE V1.02 BETA #1 I extract on Dh0: go in Amos pro and allways in winuae and in A1200 REAL say me the same this Screen:
So Really I dont know now What I Can Do with This... hope some body can help me to start use AGE.
Thanks for all in advance,
Keep with the good Work!
And Amiga 4Ever!
Amiten.
Quote
At the moment I only play i little bit with your extension AGE , but cant do work.
I extract on Dh0: go in Amos pro and allways in winuae and in A1200 REAL say me the same this Screen:
It's not actually an extension, it's more a generic library. The library comes with an AMOS wrapper and the raw machine code bundled up with it. The wrapper is just a chunk of Amos code laid out as a set of procedures that call the machine code library functions.
Setting it like this was meant to make it easier, but unfortunately AmosPro only seems to be support absolute include paths. Meaning that if folder structure is extracted differently/moved etc, than the code examples are setup to expect, Amos won't be able to locate the wrapper and you'll get that error from Amos.
So the package should be extracted to
Dh0:AGE-V102-Beta-01/ inside this folder, there should be the example files and the folders "
includes", "Manual", GFxFiles and Tools.
ie. so directory of the folder structure would look a bit like this.
Dh0:AGE-V102-Beta-01/includes
Dh0:AGE-V102-Beta-01/includes/Amos
Dh0:AGE-V102-Beta-01/includes/Amos/AGE_V085.AMOS
Dh0:AGE-V102-Beta-01/includes/Asm/Age.lib
Dh0:AGE-V102-Beta-01/includes/Manual
Dh0:AGE-V102-Beta-01/includes/Tools
Dh0:AGE-V102-Beta-01/Example_V001_Show_Picture.AMOS
Dh0:AGE-V102-Beta-01/Example_V002_Palette.AMOS
etc
etc
etc
etc
etc
Dh0:AGE-V102-Beta-01/Example_V120_Dragon3.AMOS
Hi Kevin , Thanks for your quick Response ;)
Quote
It's not actually an extension, it's more a generic library. The library comes with an AMOS wrapper and the raw machine code bundled up with it. The wrapper is just a chunk of Amos code laid out as a set of procedures that call the machine code library functions.
May be I´m a little crap jejeje, sorry but Amos Wrapper?? dont know what is this, is a Extension for Amos??
Now I try again download the AGE again in original Zip File. put in Winuae extract with MirawizARC 1.1b in DH0: Rigth! and now I get diferent error:
Variable´s Name buffer to small ???
I think now the Path is recognised rigth but something remain.
So if you know why I will very grateful .
Regards
Amiten
Hi, Just come across this thread ;D
Ive browsed through and think.
I need Amos pro "Download" and the "Beta". Will google "AMOS PRO"
I never owned An amiga! But remember seeing a demo of "Walker" i think it was called. Which looked like cool game :)
Baggey
There are a lot of engines and they do different things. Some are better in a smaller environment, some in a huge world. Some enable really complex water and visual effects, while others do great things with skelatal animation.
Hello Kevin,
Your AGE looks fantastic. I tried it couple of times in those past years. Also, did it today. However, I never succeeded in compiling any of your examples. Is it even possible? I'm experienced with Amos and I'd like to make use of your "extension" but if it can not be compiled then it misses the point. Can you help?
Quote from: Epo on March 11, 2019, 03:36:50 PM
Hello Kevin,
Your AGE looks fantastic. I tried it couple of times in those past years. Also, did it today. However, I never succeeded in compiling any of your examples. Is it even possible? I'm experienced with Amos and I'd like to make use of your "extension" but if it can not be compiled then it misses the point. Can you help?
If AmosPro can't locate the include and or it can't load the binary part of library then it wont compile or run. The paths in the examples are absolute, making the extraction path critically important to success. If you change the extraction path, you'd have to mod the paths in the examples manually.
QuoteIf AmosPro can't locate the include and or it can't load the binary part of library then it wont compile or run. The paths in the examples are absolute, making the extraction path critically important to success. If you change the extraction path, you'd have to mod the paths in the examples manually.
Thank you Kevin for quick response and sorry for delay from my part (something unexpected came up). To the point. I do understand absolute path issue. However, it does not work. I mean it works in editor but I can't make it compile without getting an error (most examples report it in line 67 but I don't think it's the line we see in editor, most probably it's internal numbering that the compiler sees only). Anyway, I've seen your video and saw you're using version 1.02 but it's not available to download (only 1.01 and 1.02-Beta-01; I'm using the latter). If you still have access to your configuration, could you please check if you're able to compile any of your examples? I'd be grateful. And thanks a lot for keeping interest in people who are interested in you old project.
Had a quick look and if you cut'n'paste the include into one of the examples, the AmosPRO compiler complains about the variable buffer overflowing. I do remember something about being able to change the heap size in Amos, but not off the top of my head..
Quote from: kevin on March 22, 2019, 10:53:53 PM
Had a quick look and if you cut'n'paste the include into one of the examples, the AmosPRO compiler complains about the variable buffer overflowing. I do remember something about being able to change the heap size in Amos, but not off the top of my head..
Kevin, your tip worked! But only with two examples: Show picture and v020_Graphic. But that's something. With others I get errors like above on the screenshot but with much further line (after 3000.)
However, after quitting from the program I must reset the Amiga because it causes some system stability problems (and does not recover all the Chip memory back.)
Quote
However, after quitting from the program I must reset the Amiga because it causes some system stability problems (and does not recover all the Chip memory back.)
On close the dellocation functions need to be called to release the buffers.. So any possible app close would have to be trapped so it calls the delloc or it'll leak.
Thank you again Kevin for taking time to respond. I'll see if I'm successful with the other examples, because those two are simply not sufficient to make a satisfactory project.
Any chance of open sourcing this? I'd love to get into the weeds and rewrite some of the inner code for the Vampire AMMX.