Page 3 of 4

Re: Plot function in z88dk

Posted: Tue Feb 06, 2018 11:34 pm
by Andy Rea
here we go again new function added zx_point

int zx_point(short x, short y)

tests the point at x,y return 1 is set , 0 if unset

zx_plot altered somewhat but usage remains the same as before

common code used by both functions now reside in a third function that should not be called from C it contains 2 assembler subroutines used by the main function routines.

anyway see ow you go with that.

regards Andy

Code: Select all

// found at https://www.z88dk.org/forum/viewtopic.php?id=6271
// Contributors: swensont, siggi, Timmy, alvin

#include <stdio.h>
#include <zx81.h>

// alvin: "It's faster to pop them or use HL to walk the stack.  The best solution is 
// Timmy's which uses CALLEE linkage so that the subroutine can pop the parameters 
// off the stack and not put them back:


// ZX81 quarter block plot/unplot/xor-plot and point (test)
// routine in ASM BY A. Rea FEB 2018

// NO BOUNDS CHECK max X 0 to 63 max Y 0 to 47
// FOR STANDARD DISPLAY MODE ONLY
// ASSUMES D-FILE IS NOT COLLAPSED 


// test a quarter block point
// if set returns 1
// if unset returns 0
int __CALLEE__ zx_point(short x, short y)
{
 __asm

 POP HL   ; HL = return address
 POP BC   ; C  = y,  and  remove y from stack (necessary for CALLEE functions)
 EX (SP),HL
 LD  B,L  ; BC = XY

 CALL CALC_DFILE_ADD
 CALL GET_BLOCK

TEST_POINT:
 LD HL,0	
 AND	B
 RET Z
 INC HL
 RET
 
	__endasm
}

// zx_plot
// x is 0 to 63
// y is 0 to 47
// pmode is 0 = unplot, 1 = plot, 2 =xor plot

static void __CALLEE__ zx_plot( short x, short y, short pmode)
{
  __asm 
  POP HL   ; HL = return address
  POP DE   ; E  = plot mode
  POP BC   ; C  = y,  and  remove y from stack (necessary for CALLEE functions)
  EX (SP),HL
  LD  B,L  ; BC = XY
  PUSH DE  ; SAVE PMODE FOR LATER
  
  CALL CALC_DFILE_ADD

	;screen address now in HL

  CALL GET_BLOCK		;returns with the current screen char in A ( or zero if non block char at screen location and the quarter block for the point we wnat in B

        ; so at this point we have the screen char ( or zero if not a valif block graphic ) in A
        ; and the quarter block graphic in B, for plotting we OR B with A result in A
        ; for unplotting we complment ( invert )  B and then AND with A
	; for XOR plot we XOR B with A
	
	ld	C,a	;save for unplot.... 

	pop	de
	dec	e
	jr	z,do_plot
	dec	e
	jr	z,xor_plot
        
	;else unplot

do_unplot:
	LD A,B
	CPL
	AND	C
	jr	plot_done

xor_plot:
	xOR	B
	jr	plot_done


do_plot:
	OR	b

plot_done:
	CP	8
	JR	C,put_char
	XOR	$8F



put_char:
	LD	(HL),A



	



    ;; note the compiler automatically adds RET on closing '}' so this is not required
   __endasm;
}


/* the following function should not be called from C
   it is meant to be called directly from assembler */
/* THE FOLLOWING FUNCTION SHOULD NOT BE CALLED FROM C
	THE 2 ASSEMBLER ROUTINE ARE CALLED DIRECTLY 
	  FROM OTHER FUNCTIONS. */

static void plot_subs ()
{

	__asm
GET_BLOCK:
	LD      A,$01        
        SRA     C              
        JR      NC,EVEN_Y

        LD      A,$04


EVEN_Y: SRA     B          
        JR      NC,EVEN_X  

        RLCA			; 1 OR 4 BECOMES 2 OR 8                

EVEN_X:
	LD	B,A		;SAVE the new pixwl block in b

	LD 	A,(HL)		;GET BYTE FROM SCREEN
	RLCA
	CP	16
	JR	NC,A_ZERO
	RRCA
	JR	NC,GOOD_CHAR
	XOR	$8F		;ELSE INVERTED CHAR
	JR	GOOD_CHAR
A_ZERO:
	XOR	A
GOOD_CHAR:
	RET

CALC_DFILE_ADD:
	;WORK OUT SCREEN BYTE FROM CO-ORDS in BC = x/y
	LD	A,C			;GET CURRENT Y POSITION 0 TO 47
	SRL	A			;A = 0 TO 23
					
	LD	E,A			;E = 1 * A
	
	LD	D,0			;DE = 1 *  A
	ADD	A,A			;A = 2* ,	MAX = 46
	ADD	A,A			;A = 4 *  , MAX = 92
	ADD	A,A			;A = 8 * , MAX =184
	ADD	A,A			;A = 16 Y , MAX = 112 AND CARRY SET
	LD 	H,0			;NO EFFECT ON CARRY
	RL	H			;PICK UP ANY CARRY	
	LD	L,A
	ADD	HL,HL		;HL = 32 * Y
	ADD	HL,DE		;HL = 33 * Y
	
	
	
	LD	A,B			;GET X POSITION 
	SRL	A			;DIVIDE BY 2
	LD	E,A
	LD	D,0			
	ADD	HL,DE		;HL NOW = SCREEN OFFSET
	LD	DE,($400C)
	ADD	HL,DE		;HL NOW = CURRENT DFILE + OFFSET
	
	INC	HL			;COMPENSATE FOR 1ST HALT IN DFILE

	RET
	  __endasm;
}



main ( )
{

  short x,y;
 printf("plotting...\n\n\n\n"); 

   /* plot points */	
   zx_plot(5,10,1);
   zx_plot(15,20,1);
	printf("point 5,10 is %d\n",zx_point(5,10));
	printf("point 6,6 is %d\n",zx_point(6,6));
	printf("point 15,20 is %d\n",zx_point(15,20));
 
   
	
   for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47,1);
	zx_plot(x, 0,1);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y,1);
	zx_plot(63, y,1);
   }

 for (x = 0; x <= 63; ++x)
   {
	zx_plot(x, 47,0);
	zx_plot(x, 0,0);
   }
   for (y = 1; y <= 47; ++y)
   {
	zx_plot(0, y,0);
	zx_plot(63, y,0);
   }
   printf("done.\n");

 for (y=1; y <= 47; ++y)
  {
    for (x=0; x<=63; x += y)
      {
         zx_plot (x,y,2);
         zx_plot (63-x, 47-y,2);
      }
   }

   
}



Re: Plot function in z88dk

Posted: Sun Feb 11, 2018 4:56 pm
by RobertK
The zx_point() function works great as well. Thank you so much, now I should have everything that I need.

BTW, the y axis of your functions is inverted (0 at the top) compared to the ZX Basic plot command (0 at the bottom).
Was this your intention? If not, then maybe it would be better to keep with the ZX Basic standard (although it's of course no big problem if this should have any technical reasons).

Another question: a Bresenham line function would be nice to have, but what is maybe more important: do you think that ASM functions to draw either a horizontal or vertical line would perform better than repeated zx_plot() calls in C for each point of the line?
If so, then zx_hline(x,y,length) and zx_vline(x,y,length) would be appropriate function names...

Re: Plot function in z88dk

Posted: Sat Feb 17, 2018 8:59 pm
by RobertK
I have made a little Moon Patrol-style scrolling mountains demo using Andy's zxplot function.

zxplot_mountains.jpg
zxplot_mountains.jpg (1.62 KiB) Viewed 7670 times

It is still too slow to be used for anything useful, but it is unbelievably fast compared to if it had been made in ZX Basic...

It also still lacks double-buffering - I have seen in the source of the z8048 game that this can be made by moving the display memory start address back and forth. But this would probably require further modifications to Andy's functions.

@Andy, see my previous posting: a zx_vline() function could speed this up a little (not much, as the mountain line ranges within a height of only 5 pixels). Do you think that such a function could be done efficiently in ASM?

Re: Plot function in z88dk

Posted: Sat Feb 17, 2018 9:35 pm
by Andy Rea
what you want there is 2 frame video buffer , 1 for odd x positions and 1 for even x positions then you only need to scroll everything left and update the last 2 quarter block columns, the LDIR block move should be quick enough for 3 character lines ( 6 block pixels) dont forget to make sure the newlines are not disturbed... or even do it a 3 lots of moves... leaving the newlines untouched... either way redrawing everything each frame is not really that practical i dont think

BTW that is rather impressive for a zx81, imagine how slow that would be in basic :lol:

regards Andy

Re: Plot function in z88dk

Posted: Sat Feb 17, 2018 10:29 pm
by sirmorris
Games don't PLOT. Just sayin' ;)

Re: Plot function in z88dk

Posted: Sun Feb 18, 2018 11:23 am
by RobertK
sirmorris wrote: Sat Feb 17, 2018 10:29 pm Games don't PLOT. Just sayin' ;)
But maybe a game could first plot and then scroll. :D

If anyone wants to turn my "simple full-plot scrolling" demo into real scrolling as described by Andy: go for it!

Re: Plot function in z88dk

Posted: Sun Feb 18, 2018 11:30 am
by siggi
sirmorris wrote: Sat Feb 17, 2018 10:29 pm Games don't PLOT. Just sayin' ;)
But my game "AUTORENNEN" does it:
autorenn.p
(5.65 KiB) Downloaded 321 times
:mrgreen:
Siggi

Re: Plot function in z88dk

Posted: Sun Feb 18, 2018 3:03 pm
by Andy Rea
Tron trails does a bit of plotting.. .

Re: Plot function in z88dk

Posted: Sun Feb 18, 2018 5:19 pm
by sirmorris
OH ALL RIGHT ALL RIGHT so games _do_ PLOT :P :lol:

Re: Plot function in z88dk

Posted: Mon Feb 26, 2018 12:37 pm
by siggi