A minimal CPC mode 0 demo with z88dk

Amstrad CPC and NC systems
Post Reply
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

A minimal CPC mode 0 demo with z88dk

Post by Timmy »

So here's a really basic Mode 0 sprite demo for the CPC.

It's very rudimentary and there will be improvements to this later (hopefully), may be or may not be in this thread though.

The hardest part of this is coming up with a sprite that looks good in 8x16. (And drawing it. And converting this to the cpc special colour scheme. Had to wrote a tool for that too.)

Anyway, here's some code:

Code: Select all

// test 20230418 Timmy, a simple demo of CPC mode 0

// I've built this with:
// zcc +cpc -lndos -lm -subtype=dsk -create-app -zorg=16384 -o 9 cpctest9.c

#include <cpc.h>
#include <stdio.h>
#include <strings.h>

extern const uchar sprite1[];

#asm
._sprite1
DEFB 0x00, 0x30, 0x70, 0x00
DEFB 0x40, 0x85, 0x1A, 0xA0
DEFB 0x40, 0x52, 0x0F, 0xA0
DEFB 0x81, 0xF0, 0xA5, 0x70
DEFB 0xD0, 0xF0, 0xA5, 0x70
DEFB 0xD0, 0xF0, 0xA5, 0x70
DEFB 0xD0, 0xF0, 0xA5, 0x70
DEFB 0xD0, 0xF0, 0xF0, 0x5A
DEFB 0xD0, 0xDA, 0xDA, 0x5A
DEFB 0xC5, 0xE5, 0xE5, 0x5A
DEFB 0xC5, 0xE5, 0xE5, 0x5A
DEFB 0xD0, 0xDA, 0xDA, 0x5A
DEFB 0xF0, 0xF0, 0xF0, 0xF0
DEFB 0x0F, 0x0F, 0x1E, 0x5A
DEFB 0xF0, 0x5A, 0x5A, 0xF0
DEFB 0x00, 0xF0, 0xF0, 0x00
#endasm

int __FASTCALL__ nextline(int p) __naked
// who knew making a sprite in CPC mode 0 is so hard?!!
{
	#asm
		ld a, h
		add a, 8
		jr c, overflow
		ld h, a
		ret
		
	.overflow
		add hl, 0xc850
		ret
	#endasm
}

void __FASTCALL__ putsprite2(int p) __naked
// this erases the sprite before moving
// replace all 0x00 to 0xF0 to see how this sprite looks like in reality
// 00 is the background colour
{
	#asm
		push hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		pop hl
		call _nextline
		push hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		pop hl
		call _nextline
		ld b, 12
		
	.spr2loop 
		push hl
		ld (hl), 0x00
		inc hl
		inc hl
		inc hl
		ld (hl), 0x00
		pop hl
		call _nextline
		djnz spr2loop
		
		push hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		pop hl
		call _nextline
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		inc hl
		ld (hl), 0x00
		ret
	
	#endasm
}

void putsprite(uchar *p)
// the c version of the putsprite3()
{
	uchar *r;
	uchar *q;
	int x,y;

	q = sprite1;
	
	//p = 0xC4B0;
	for (y=0; y<8; y++)
	{
		r = p;
		for (x=0; x<4; x++)
		{
			*r++ = *q++;
		}
		//p += 0x800 - 4;
		p = nextline(p);
	}

	//p = 0xC4B0 + 0x50;
	for (y=0; y<8; y++)
	{
		r = p;
		for (x=0; x<4; x++)
		{
			*r++ = *q++;
		}
		//p += 0x800 - 4;
		p = nextline(p);
	}

}

void __FASTCALL__ putsprite3(int p) __naked
{
	#asm
		ld de, _sprite1
		
		ld b, 16
		
	.spr3loop 
		push bc
		push hl
		ex de, hl
		ldi
		ldi
		ldi
		ldi
		ex de, hl
		pop hl
		call _nextline
		pop bc
		djnz spr3loop
		
		ret
	
	#endasm
}

int __CALLEE__ pack2 (uchar l, uchar h) __naked __z88dk_sdccdecl
// returns: hl
{
	#asm
	pop bc
	pop hl
	push bc
	ret
	#endasm
}

int __CALLEE__ get_address (uchar x, uchar y) __naked __z88dk_sdccdecl
// returns: screen address
// absolutely not the most efficient way to do this, but it works for now.
{
	#asm
		pop bc
		pop de
		push bc
		
		ld hl, 0xC000
		
		ld a, d
		and 7
		or a
		jr z, ga1a
		ld b, a
	.ga1
		add hl, 0x800
		djnz ga1
	.ga1a
		ld a, d
		srl a
		srl a
		srl a
		or a
		jr z, ga2a
		ld b, a
	.ga2
		add hl, 0x50
		djnz ga2
	.ga2a
		ld d, 0
		add hl, de
		ret
	#endasm
}

main(){
		uchar c;
		uchar *p;
		int dx, dy;
		uchar x,y;

	   cpc_DisableFirmware();  // optional

       cpc_SetMode(0);         // optional

	   p = 0xC140 + 1;
	   c = 0;
	   dx = 1; dy = 2;
	   y = 40; x = 10;
	   
	   while (1)
	   {	   
		   p = get_address(x,y);
		   putsprite2(p);

		   x += dx;
		   y += dy;
		   if ((y>150) || (y<=2)) dy = -dy;
		   if ((x>70) || (x<=2)) dx = -dx;
		   
		   p = get_address(x,y);
		   putsprite3(p);
		   
		   // a delay routine
			#asm
				ei
				ld b, 12
				.ko
				halt
				djnz ko
				di
			#endasm
	   }
	   
}

=== END POST ===
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: A minimal CPC mode 0 demo with z88dk

Post by dom »

I've not actually used it, but I believe cpcrslib which is in the library supports sprites in mode 0. There seems to be an example on GitHub here: https://github.com/cpcitor/cpcrslib/blo ... tes/code.c

By pure coincidence I've finally implemented graphics for all 3 official screen modes which has been on my todo list for about 4 years.
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

Re: A minimal CPC mode 0 demo with z88dk

Post by Timmy »

dom wrote: Wed Apr 19, 2023 8:29 pm I've not actually used it, but I believe cpcrslib which is in the library supports sprites in mode 0. There seems to be an example on GitHub here: https://github.com/cpcitor/cpcrslib/blo ... tes/code.c
I understand how the regular sprite routine in cpcrslib works, but only after making this demo. Surprsingly it's less intuitive if you just read that code first. The tricky part is in the data.
By pure coincidence I've finally implemented graphics for all 3 official screen modes which has been on my todo list for about 4 years.
Congratulations! I think this is a great achievement! And it may help with more adoption of this target.

(No, I have no idea how <graphics.h> works in this case, I never used graphics myself. But that's only because I like to write my own sprite routines. That usually helps me with the understanding how a particular screen works. But I believe it's really useful for other people.)
Post Reply