English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 17 October 2019, 23:07   #1
mcgeezer
Registered User

 
Join Date: Oct 2017
Location: Sunderland, England
Posts: 1,488
Game Programming Framework

So after a fair bit of thought on what to do next, I've long set my heart on doing some Game programming tutorial streams for the Amiga.

With that said, looking back I made many many mistakes when coding Rygar... things that were just bad habits or because I was under a time constraint to finish the game for the competition.

So what I'd like to do is come up with a set of assembler functions that facilitate making game coding easier, while the implementation will be assembler I'll try and comform to high level languages like C (although I've never written any C before).

So here goes... I've documented (but not written) a couple of functions to set the tone, the idea being writing the actual function will be the assembler tutorial and the hope is that a picture of how to build a game will slowly come across to following...with better games being made for the Amiga.

Here are the off the cuff high level functions (just a brain dump)...I have more to add.

Code:
[+] rawHandle = amgLoadAndUnpackRncAsset(*name, bufsize, memtype)
[+] assetHandle = amgParseAsset(rawHandle)

[+] cameraHandle = amgCreateScreenBuffer(XSize, YSize, BitPlanes)
        Allocate screen memory, Creates Bitplane Handles
	
[+] copperHandle = amgCreateInitalCopperList(cameraHandle,paletteHandle)
        Build a default copper list from a camera handle.
	
[+] spriteSheetHandle = amgGenerateSpriteSheet(assetHandle, *Buffer, SpriteCutSize, MaxCuts, bool Mask)
        Build a list of pointers to the sprites and their masks	
	
[+] spriteHandle = amgCreateSprite(spriteSheetHandle)
[+] result = amgSetSpriteHandler(spriteHandle, *Address, State)
[+] result = amgSetPlayerSprite(spriteHandle *Address)
[+] result = amgDestroySprite(spriteHandle)	

[+] spriteAnimHandle = amgCreateSpriteAnimation(spriteHandle, spriteAnimationType)
[+] result = amgAppendSpriteAnimationFrame(spriteAnimHandle,*Handler, Frame, Speed)
[+] result = amgSetSpriteAnimation(spriteAnimHandle, bool [loop|term])

[+] SpriteNumber = amgCastSprite(spriteHandle,initXpos,initYpos,State)
[+] result = amgSetSpriteStatus(spriteHandle, bool State)
[+] result = amgSetSpriteAnimationSpeed(spriteAnimHandle)

[+] tileHandle = amgSetTileSheetAttributes = (assetHandle, sizeX, size Y)
[+] result = amgSetTilePlatform(tileId,tileHandle,spriteHandle,maskId)
[+] result = amgSetTileObstacle(tileId,tileHandle,spriteHandle,maskId)
[+] result = amgSetTileCeiling(tileId,tileHandle,spriteHandle,maskId)

[+] mapHandle  = amgCreateTileMap(rawHandle,xSize,ySize,size)

[+] canvasHandle = amgCreateCanvas(mapHandle, tileHandle)
[+] result = amgSetCanvasLimits(canvasHandle,x1,y1,x2,y2)
[+] result = amgSetCanvasPlayerLimits(canvasHandle,spriteHandle,x1,y1,x2,y2)

[+] amgBlitTileToCamera(canvasHandle,cameraHandle, sourceTile, destTile)
[+] copperList = amgDrawCurrentCameraPosition(canvasHandle,cameraHandle)

[+] copperListHandle = amgSetCanvasMode(canvasHandle,mode)
                        Mode can be:
                                0 = Static
                                1 = Horizontal Bi-Directional
                                2 = Horizontal Right
                                3 = Horizontal Left
                                4 = Vertical Bi-Directional
                                5 = Vertical Down
                                6 = Vertical Up
                                7 = 8 Way
                                10 = Dual Playfield Static
                                11 = Dual Playfield Horizontal Bi-Directional
                                12 = Dual Playfield Horizontal Right
                                13 = Dual Playfield Horizontal Left
                                14 = Dual Playfield Vertical Bi-Directional
                                15 = Dual Playfield Vertical Down
                                16 = Dual Playfield Vertical Up
                                17 = Dual Playfield 8 Way
				

[+] amgSetCanvasCameraPosition(canvasHandle,cameraHandle,x1,y1,x2,y2)                              ; Can use this to scroll around

And here's the first two functions documented:

Code:
NAME
        amgLoadAndUnpackRncAsset - Load and unpack file


SYNOPSIS
        rawHandle = amgLoadAndUnpackRncAsset(*name, bufsize, memtype)
        d0                                  a0     d0       d1


FUNCTION
        The file 'name' should be a ProPacked file using method 1 or 2.
        Memory of the required type and bufsize in bytes is allocated using AmigaDos
        malloc(), If the supplied bufsize is 0 then the packed file header is read to find
        the number of first before loading and unpacking the file.
        The memtype argument can either by MEMF_CHIP to allocate chip ram, MEMF_FAST to
        allocate Fast Ram or MEMF_ANY to allocate any available ram type, however should
        fast ram be available as well as chip then fast will be used as a priority.


INPUTS
        name - (a0) pointer to null-terminated file name of asset to load.

        bufsize - (d0) buffer size in bytes to allocate

        memtype - (d1) MEMF_CHIP | MEMF_FAST | MEMF_ANY


RESULTS
        rawHandle - (d0) handle code for the loaded asset


ERRORS
        error - (d0) failure to load and unpack the asset will result in any of the following
                                  errors.

                        -1 - File not found
                        -2 - Unable to allocate ram type
                        -3 - Unpack failed
                        -4 - Max handles reached

Code:
NAME
        amgParseAsset - Parse and store the information found in a loaded asset


SYNOPSIS
        assetHandle = amgParseAsset(rawHandle)
        d0                           d0


FUNCTION
        The handle supplied should be the result from calling the 'amgLoadAndUnpackRncAsset'
        function.  The supported assets are Protracker Music Modules, 8SVX Sound samples and
        uncompressed Amiga ILBM image files.  Upon successful execution of the function
        a new handle is returned with the requested information parsed based on the found
        asset type.  See the AMG handles structure for more information.


INPUTS
        handle (d0) - A handle number that has previously been returned from
                                  'amgLoadAndUnpackRncAsset'.


RESULTS
        assetHandle (d0) - Asset handle number.

ERRORS
        error - (d0) failure to parse information found with the associated handle.

                        -1 - Supplied handle not found
                        -2 - No supported Interchangable File Format header could be found (FORM)
                        -3 - Failed to locate Bitmap Header (BMHD)
                        -4 - Failed to locate Body Header (BODY)
                        -5 - Failed to locate Colour Map header (CMAP)
                        -6 - Asset is compressed
                        -7 - Failed to locate Sample header (8SVX)
                        -8 - Failed to locate Module header (MOD)

SEE ALSO
And here's the handle structures...

Code:
Struct handles
        STATUS                  X       byte    (-1 - invlaid, 0 - valid)                                      * AmgLoadAndUnpackRncAsset()
        ADDRESS                 X       long    Pointer in ram to asset                                        * amgLoadAndUnpackRncAsset()
        TYPE                    X       byte    (-1 - undefined, 					       * amgParseAsset()
						  0 - IFF Image, 
						  1 - Music Module, 
						  2 - Sound Sample )    
        IMGIFFSIZE              X       word    Size in bytes of entire                                        * amgParseAsset()
        IMGBODYSIZE             X       long    Size in bytes of body                                          * amgParseAsset()
        IMGCMAPSIZE             X       long    Size in bytes of colour map                                    * amgParseAsset()
        IMGBODYPTR              X       long    Pointer to body data origin                                    * amgParseAsset()
        IMGCMAPPTR              X       long    Pointer to cmap data origin                                    * amgParseAsset()
        IMGCMAPTYPE             X       byte    Type of colour map 0=12bit/1=24bit                             * amgParseAsset()
        IMGWIDTH                X       word    Size in pixels of image width                                  * amgParseAsset()
        IMGDEPTH                X       word    Size in pixels of image depth                                  * amgParseAsset()
        IMGPLANESIZE    	X       byte    Number of bitplanes in the image                               * amgParseAsset()
        IMGBYTEWIDTH    	X       byte    Number of bytes in width of the image                          * amgParseAsset()
        IMGMODULO               X       byte    Image modulo                                                   * amgParseAsset()
        8SXIFFSIZE              X       word    Size in bytes of entire asset                                  * amgParseAsset()
        8SXBODYSIZE             X       long    Size in bytes of body data                                     * amgParseAsset()
        8SXPERIOD               X       word    Sample period                                                  * amgSetAssetData()


result = amgSetAssetData(handle, offset, data)
d0                         d0     d1     d2

result = amgGetAssetData(handle, offset)
d0                         d0     d1

Index to handle data
*ptr = amgIndexToHandle(handle)
  a0

So the hope is that I can build on this. As I have a strong Unix/Shell/Python background I tend to operate everything on file handles and OOP so I'm hoping to take those principles into this.

This project might not go very far... but then again, it might really be useful.
It's certainly something I can take at a much slower pace than coding something like Rygar.

Ideas and comments as usual are really welcome.

Geezer
mcgeezer is offline  
Old 17 October 2019, 23:42   #2
Spec-Chum
Registered User

 
Join Date: Dec 2016
Location: England
Posts: 85
Awesome!

You probably don't remember but I asked you about this on Facebook few weeks ago, so glad it looks like it's going ahead!
Spec-Chum is offline  
Old 18 October 2019, 00:15   #3
tolkien
AmigaMan

tolkien's Avatar
 
Join Date: Oct 2012
Location: Castro Urdiales/Spain
Posts: 544
great! I tick this thread to favourites!
tolkien is offline  
Old 18 October 2019, 00:23   #4
Spec-Chum
Registered User

 
Join Date: Dec 2016
Location: England
Posts: 85
Quote:
Originally Posted by mcgeezer View Post
(although I've never written any C before).
I really doubt a man of your skill will have much issues mate, if I'm honest.

C can be made very asm like, indeed that was what it was designed for, as an almost 1 to 1 correlation with asm.

As an example I've decided to code Scoopex's tutorials into C, so I'm not just copying and pasting. Here's tut4. You can most probably guess the code this produces, as it's virtually identical to Photon's source.

Code:
#include <exec/types.h>

#define VPOSR 0xdff004
#define VHPOSR 0xdff006
#define INTENAR 0xdff01c
#define INTENA 0xdff09a
#define COLOR00 0xdff180
#define CIAPRAA 0xbfe001

int main()
{
	volatile UBYTE *vhposr = (UBYTE *)VHPOSR;
	volatile UBYTE *vposr_lo = (UBYTE *)VPOSR + 1;	// point to low byte
	UWORD *color00 = (UWORD *)COLOR00;
	UWORD *intena = (UWORD *)INTENA;

	// line starting position
	UBYTE yPos = 0xac;

	// line direction
	BYTE yDir = 1;

	// save interrupts
	UWORD oldInt = *(UWORD *)INTENAR;

	// disable all interrupts
	*intena = 0x7fff;

	// do main loop until mouse pressed
	while(*(volatile UBYTE *)CIAPRAA & 64)
	{
		// wait for start of frame
		if((*vposr_lo & 1) == 0 && *vhposr == 0x2c)
		{
			*color00 = 0;	// bg black

			// update line y position
			yPos += yDir;

			// bounce line
			if(yPos > 0xf0 || yPos < 0x40)
			{
				yDir = -yDir;
			}

			// do literally nothing until we reach yPos
			while(*vhposr != yPos)
			{}
			*color00 = 0xfff;	// bg white

			// now do nothing until we're not on yPos
			while(*vhposr == yPos)
			{}
			*color00 = 0x116;	// bg blue
		}
	}

	// restore interrupts
	*intena = oldInt | 0xc000;	
	
    return 0;
}
On the other side of the coin, you can use the headers to (to some) make your life a little easier, here's my asm takeover code I converted to C:

Code:
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <exec/execbase.h>
#include <hardware/cia.h>
#include <hardware/custom.h>
#include <graphics/gfxbase.h>

extern struct GfxBase *GfxBase;
extern struct Custom custom;
extern struct CIA ciaa;

struct View *OldView;
static UWORD oldInt;
static UWORD oldDMA;

__chip UWORD copperlist[] =
{
        0x0106, 0x0000,     // AGA - BPLCON3
        0x01fc, 0x0000,     // AGA - Slow FMODE

    	0x0180, 0x0f00,		// Colour00 = red
        0x8001, 0xff00,     // wait until VPos = 0x80
        0x0180, 0x0fff,     // Colour00 = white
        0xd001, 0xff00,		// wait until VPos 0xd0
        0x0180, 0x000f, 	// Colour00 = blue
		
		0xffff, 0xfffe		// end list
};

int main()
{
	// Save original view
	OldView = GfxBase->ActiView;

	// Set clean view
	LoadView(NULL);
	WaitTOF();
	WaitTOF();

	// Save interrupts and DMA
	oldInt = custom.intenar;
	oldDMA = custom.dmaconr;

	// disable all interrupts
	custom.intena = 0x7fff;

	// disable all DMA
	custom.dmacon = 0x7fff;

	// set cl1 to our copper
	custom.cop1lc = (ULONG)copperlist;
	
	// enable selected DMA
	custom.dmacon = 0x8280;	// No Blitter or sprites, only copper

	// loop until mouse clicked
	while(ciaa.ciapra & CIAF_GAMEPORT0)
	{
		// do nothing
	}

	// restore interrupts and DMA
	custom.dmacon = oldDMA | 0x8000;
	custom.intena = oldInt | 0x8000;

	// restore orginal copper
	custom.cop1lc = (ULONG)GfxBase->copinit;

	// restore old view
	LoadView(OldView);
	WaitTOF();
	WaitTOF();

	return 0;
}

Last edited by Spec-Chum; 18 October 2019 at 00:41.
Spec-Chum is offline  
Old 21 October 2019, 00:57   #5
mcgeezer
Registered User

 
Join Date: Oct 2017
Location: Sunderland, England
Posts: 1,488
So I've implemeted a couple of these functions now and added another few.

The function added is amgUnloadAsset() - it's pretty simple.

Code:
NAME
        amgUnloadAsset - Release handle and ram held by an asset


SYNOPSIS
        amgUnloadAsset(assetHandle)
                         d0


FUNCTION
        The specified handle is marked with a status of unused within its structure.
	The address and length pointers of the handle are left in tact, these are
	subsequently used to deallocate the ram of the asset using LVOFreeMem().


INPUTS
        handle - (d0) A previously allocated handle using amgLoadAndUnpackRncAsset().



RESULTS
        NULL


ERRORS

As I've implemented the functions I can post them here.

We have six files in total

main.asm - this has the main calling program.
loader.asm/loader.dat - this is what does the load header, allocate ram, read packed file, unpack file.
handle.asm/handle.dat - this contains the code for managing handles
unpack.asm - RNC unpacker


The main program looks like this, it simply reads the header of an RNC packed file, reads the unpacked size from the header, allocates that amount of ram, loads and unpacks the whole file to that allocated ram, allocates a handle for that asset that has been loaded....then... deallocates the handle and frees ram. This is pretty much a key aspect into managing assets in an Amiga game.

Code:
ExecBase:               	equ     4

        cseg

        basereg data,a4
        near    a4

CODE_BASE:

	bra	MAIN

	CNOP	0,4
		
        include i/custom.i              ; Custom Register definitions
        include i/cia.i                 ; CIA Hardware definitions
        include 'exec/types.i'
	include 'exec/exec.i'
	include 'exec/exec_lib.i'
	include 'libraries/dos.i'
	include 'libraries/dos_lib.i'
        include 'hardware/blit.i'
        include 'hardware/dmabits.i'	
        include s/unpack.asm
	include s/loader.asm
	include s/handle.asm
	
	
MAIN:
; Reserve a4 and a5 for global pointers.
	lea	data,a4					
	lea	CHIPBASE,a5				

; Open the DOS library
	move.l  ExecBase,a6				; handle[d0] = OpenLibrary=(version[d0],libname[a1])
	lea     DOSNAME(a4),a1
	moveq   #0,d0
	jsr     _LVOOpenLibrary(a6)
	move.l	d0,DOSBASE(a4)				; save DOSBASE for file reading

	lea	asset_lower(a4),a0			; rawHandle = amgLoadAndUnpackRncAsset(*name[a0], memtype[d1])
	moveq	#0,d0
	moveq	#MEMF_CHIP,d1
	bsr	amgLoadAndUnpackRncAsset
; d0 has allocated handle number

; now lets unload the asset from memory.
	bsr	amgUnloadAsset				; amgUnloadUnpackedAsset(handle[d0])
	
	move.l  ExecBase,a6				; Close the DOS library.
	move.l  DOSBASE(a4),a1
	jsr     _LVOCloseLibrary(a6)

; End program
        moveq   #0,d0
        rts
	
; Data section here.

        dseg
	

dats:
	include s/loader.dat
	include s/handle.dat

DOSBASE:	dc.l	0
DOSNAME:	dc.b	'dos.library',0
		even

asset_lower:	dc.b	"dh1:Rygar/ry_lower.rnc",0		; Packed RNC file to load.
		even

data:

loader.asm looks like this...

Code:
mode_old   =1005
mode_new   =1006
	
; rawHandle = amgLoadAndUnpackRncAsset(*name, memtype)
;    d0                                  a0     d1

amgLoadAndUnpackRncAsset:
	movem.l	d1-d7/a0-a1,-(a7)		; Save Registers
	move.l	d1,d5				; Save Requested Memory Type
	move.l	a0,d6				; Save filename pointer (we'll be needing it twice)
	
; Open the file for reading
	move.l	a0,d1				; handle[d0] = LVOOpenFile(filename[d1],mode[d2])
	move.l  DOSBASE(a4),a6       
        move.l  #mode_old,d2
        jsr     _LVOOpen(a6)         		
	tst.l	d0				
	bmi	.open_error
	
; Read the RNC header file
	move.l	d0,d4				; Save handle for LVOClose
	
	lea	amgRncHeaderBuffer(a4),a0	; Buffer to read RNC header bytes
	move.l	a0,d2				; bytes[d0] = LVORead(handle[d1],buffer[d2],size[d3])		
	moveq	#20,d3				
        jsr     _LVORead(a6)         		
	tst.l	d0				; Was there an error?
	bmi	.header_error
	cmp.l	d0,d3				; Did we read the correct number of bytes?
	bne	.read_error
; Close the file
	move.l	d4,d1				; result = LVOClose(handle[d1])
        move.l  DOSBASE(a4),a6       	
        jsr     _LVOClose(a6)        
	
; Check the RNC header
	lea	amgRncHeaderBuffer(a4),a0	; Get pointer to the read header
	move.l	(a0),d0
	lsr.l	#8,d0
	cmp.l	#"RNC",d0			; Is it RNC?
	bne	.rnc_error

; Allocate ram based on RNC header	
	move.l	4(a0),d0			; address[d0] = LVOAllocMem(buffsize[d0],MEM_TYPE[d1])
	move.l	d5,d1				
        move.l  ExecBase,a6
        jsr     _LVOAllocMem(a6)
	tst.l	d0
	bmi.s	.alloc_error
	
	move.l	d0,d4				; Save the allocated buffer origin
	
; Open the file again and read it.
	move.l	d6,d1				; handle[d0] = LVOOpenFile(filename[d1],mode[d2])
	move.l  DOSBASE(a4),a6       
        move.l  #mode_old,d2
        jsr     _LVOOpen(a6)         		
	tst.l	d0
	bmi.s	.open_error
	move.l	d0,d5				; Save handle for read and close.
	
	
; Read the entire file
	move.l	d4,d2				; bytes[d0] = LVORead(handle[d1],buffer[d2],size[d3])
	move.l	#$ffffff,d3		
        jsr     _LVORead(a6)         	
	tst.l	d0
	bmi.s	.read_error
	
; Close the file
	move.l	d5,d1				; result = LVOClose(handle[d1])
        move.l  DOSBASE(a4),a6       
        jsr     _LVOClose(a6)        

; Allocate a new handle here for the asset that was just read.
	bsr	amgAllocateHandle		; assetHandle[d0], handleOrigin[a0] = amgAllocateHandle()
	tst.l	d0
	bmi.s	.handle_error
	move.l	d0,d1				; Save handle
	
	move.l	d2,a1
	move.l	d4,HANDLE_STRUCT_ADDRESS(a0)	; Save the address of the asset in ram in the handle
	move.l	4(a1),HANDLE_STRUCT_LENGTH(a0)	; Save the length of the asset in ram in the handle
	
	move.l	a1,a0				; UnpackSize[d0] = Unpack[source[a0],dest[a0]
	bsr	Unpack
	
; Verify the unpack size against what was in the header
	lea	amgHandlesStruct(a4),a0
	lsl.w	#4,d1
	cmp.l	HANDLE_STRUCT_LENGTH(a0,d1),d0
	bne.s	.unpack_error
	
	move.l	d1,d0
	


	bra	.exit				; All done.
	        	
.open_error:
	moveq	#ERROR_HANDLE_FILE_OPEN,d0
	bra.s	.exit
.header_error:
	moveq	#ERROR_HANDLE_HEADER_NOT_FOUND,d0
	bra.s	.exit
.alloc_error:
	moveq	#ERROR_HANDLE_ALLOCATE_FAIL,d0
	bra.s	.exit
.read_error:
	moveq	#ERROR_HANDLE_FILE_READ,d0
	bra.s	.exit
.rnc_error:
	moveq	#ERROR_HANDLE_RNC,d0
	bra.s	.exit
.handle_error:
	moveq	#ERROR_HANDLE_GENERIC,d0
	bra.s	.exit
.unpack_error:
	moveq	#ERROR_HANDLE_UNPACK,d0
	bra.s	.exit
	nop
.exit:	
	movem.l	(a7)+,d1-d7/a0-a1
	rts
	



; d0=handle number
amgUnloadAsset:
; Now lets release the handle and the memory we just allocated.
	lsr.w	#4,d0
	bsr	amgReleaseHandle		; handleOrigin[a0] = amgReleaseHandle(assetHandle[d0])

	move.l	HANDLE_STRUCT_ADDRESS(a0),a1
	move.l	HANDLE_STRUCT_LENGTH(a0),d1
	move.l  ExecBase,a6
	jsr     _LVOFreeMem(a6)
	rts
loader.dat looks like this

Code:
			CNOP	0,4

amgRncHeaderBuffer:	
			ds.w	20

			CNOP	0,4

handle.asm looks like this...

Code:
maxHandles:			equ	20		

; Error return codes for handles.
ERROR_HANDLE_FILE_OPEN:		equ	-1
ERROR_HANDLE_HEADER_NOT_FOUND:	equ	-2
ERROR_HANDLE_ALLOCATE_FAIL:	equ	-3
ERROR_HANDLE_FILE_READ:		equ	-4
ERROR_HANDLE_RNC:		equ	-5
ERROR_HANDLE_GENERIC:		equ	-6
ERROR_HANDLE_UNPACK:		equ	-7


; Handle structure indexes
HANDLE_STRUCT_STATUS:		equ	0
HANDLE_STRUCT_TYPE:		equ	1
HANDLE_STRUCT_ADDRESS:		equ	2
HANDLE_STRUCT_LENGTH:		equ	6

; OUTPUTS:
; Returns new handle number in d0
; Returns pointer to handle structure in a0
amgAllocateHandle:
	move.l	d7,-(a7)
	lea	amgHandleAllocs(a4),a0
	moveq	#0,d0
	moveq	#maxHandles-1,d7
.loop:	tst.w	(a0)+
	bmi.s	.found
	addq.w	#1,d0
	dbf	d7,.loop
	moveq	#-1,d0
	bra.s	.exit
	
.found:
	subq.w	#2,a0
	move.w	d0,(a0)
.exit:
	move.l	d0,d7
	lsl.w	#4,d7
	lea	amgHandlesStruct(a4),a0
	add.l	d7,a0
	move.b	d0,(a0)

	move.l	(a7)+,d7
	rts
	

; Frees up a handle previously allocated with amgAllocateHandle()
; INPUT [d0] = handle to release	
amgReleaseHandle:
	lea	amgHandleAllocs(a4),a0
	move.w	#-1,(a0,d0*2)

	lea	amgHandlesStruct(a4),a0
	lsl.w	#4,d0
	add.l	d0,a0
	move.w	#-1,(a0)
	rts
and handle.dat like this...

Code:
amgHandleCurrent:	dc.w	0			; Current handle pointer

amgHandleAllocs:	
			rept	maxHandles
			dc.w	-1
			endr
			
amgHandlesStruct:
			rept	maxHandles
			dc.b	-1			; Status -1/0
			dc.b	-1			; Type (-1 = unallocated)
			dc.l	0			; Address
			dc.l	0			; Length
			dc.b	"HANDLE"		; Padding.
			endr

Also included in the archive I have uploaded is the RNC unpack code.

And a link to the source code is here.

For those who want to follow along I will do a video showing setting up the tool chain and debugging the source here, feel free though to give it a try yourself if you want to race ahead.

http://109.228.4.199/downloads/Tutorial%201.zip
mcgeezer is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
API2 modern programming framework! AMIGASYSTEM support.Apps 1 21 February 2019 18:05
Haujobb Amiga Framework released stainy Coders. Releases 6 03 February 2019 19:02
Non-game programming - what does that leave me with? TenLeftFingers Coders. General 56 03 February 2016 02:59
Amiga 3D game programming Steve Coders. General 37 17 June 2013 23:15
C# Framework bburtonpa Coders. General 0 02 June 2010 15:46

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 17:41.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.
Page generated in 0.06515 seconds with 15 queries