First steps into Z88DK...and many more to come!

Discuss game and other programming topics not specifically covered in another forum

Moderator: Programming Moderators

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Sun Nov 12, 2017 3:19 pm

Sadly missed the update again, but it did allow me to resolve the multi-touch issue I had with Android. Long story cut short; just allocate memory at the start of an app and be done with it. ^_^

On the Spectrum front, I'm going to have another gander...

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Wed Nov 29, 2017 8:00 pm

Sorry to be out of touch on the Spectrum side of things, but its been hectic for me of late on other projects.

Some good news in that I'm making progress on that "Snes-mode-7" thingy I was on about, and its done me a lot of good. The nice thing is that the time I spent programming the Spectrum 48K has helped me immensely to prepare for it. I seem to have the distance-projecting thing sorted but now left with the far simplier problem of field-of-view. But I know I can overcome that.

Just having thoughts about whether or not the NEXT would be capable of a game like F-Zero. And having just got a Buffalo SNES control pad, I'm wondering if the NEXT could use it. Saying that, a game like F-Zero obviously would be caining the hell out of cosine-and-sine functions!

Anyway, once I have the mode-7 thing done I will return to the Spectrum. Its too close to my heart to let go, if you get my meaning.

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Thu Jan 04, 2018 3:53 pm

Happy new year!

I took Christmas off after having nailed the Mode-7 demo...

http://codestarlight.com/images/mode7.jpg

I go into 2018 with reduced hours at work so I can catch up with my coding projects, and hopefully get some google-play stuff done. Spectrum wise, I've spent today reviewing the work I'd done last year and tidying up my files. It seems my last demo was an attempt at a scrolling map. Its obviously more involved than the demos that came before it, so I might just show the code here as it develops.

I might consider updating on Friday nights instead of the usual Sundays...

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Fri Jan 05, 2018 6:16 pm

Heres a new source file...

Code: Select all

/*********************************************************
 * "mapscroll.c" by S.A Ray (SamusDrake)				 
 *							 
 * This program is a tile-map scrolling demo; displaying
 * only the tiles the view can see on a world map.
 *
 * An example of this would be the world map screen in many 
 * an early japanese 2D rpg.
 *
 *********************************************************
 *
 * NOTE: This source file is a work-in-progress, as it is 
 *       a more complex project.  Unlike previous examples,
 *	 the code might be a bit sloppy. 
 *
 * LAST UPDATE: 5th January, 2018.
 * 
 *********************************************************
 *
 * In the target Spectrum model, the 48K, the screen
 * memory map starts and finishes at the following
 * addresses...
 *
 * start:    0x4000	(16384)
 * finish:   0x57FF	(22528)
 *
 * The size of the screen memory map is 6144 bytes long.
 * That does not include the colour memory map.
 *
 *********************************************************
 *			 
 * Spectrum screen resolution: 256 * 192 pixels
 * Back buffer memory usage:  6144 bytes;    
 *
 * Compile with: zcc +zx -lm -lndos -create-app mapscroll.c
 *
 *********************************************************         
 *
 * Written using z88dk.
 *
 * Thank you to the community at the ZX Spectrum 
 * Next forum, and the Speccy community at large.
 *
 *********************************************************/ 


#include <stdio.h>

#define WORLD_MAP_DIMENSION	64
#define WORLD_MAP_ARRAY_SIZE	4096

void 		init_world_map();
unsigned char 	get_world_map_tile( unsigned char x, unsigned char y );
void 		set_world_map_tile( unsigned char new_tile_value, unsigned char x, unsigned char y );
void		create_sprite_values();

unsigned char world_map[ WORLD_MAP_ARRAY_SIZE ];

unsigned char bits_in_byte[8]= { 128, 64, 32, 16, 8, 4, 2, 1 };

// Sprite in its basic form of 64 elements( 8 * 8 pixels )
unsigned char sprite[64]=
{
	1,0,0,0,0,0,0,1,
	0,1,0,0,0,0,1,0,
	0,0,1,0,0,1,0,0,
	0,0,0,1,1,0,0,0,
	0,0,0,1,1,0,0,0,
	0,0,1,0,0,1,0,0,
	0,1,0,0,0,0,1,0,
	1,0,0,0,0,0,0,1
};

// This is the array which will hold the compressed version of the sprite array.
unsigned char sprite_compressed[8];

/******************************************************************************************
 * MAIN AND INITIALIZATION FUNCTIONS
 ******************************************************************************************/


/**
 * MAIN FUNCTION.
 */
main()
{
	int 		index;
	unsigned char 	current_tile;

	clg();

	init_world_map();

	set_world_map_tile( 128, 32, 32 );
	set_world_map_tile( 57,  54, 17 );
	set_world_map_tile( 234, 12, 4  );

	// Search all the tiles for any that were "set" and 
	// report their values.
	printf("*** LIST OF SET TILES ***\n\n");
	
	for( index = 0; index < WORLD_MAP_ARRAY_SIZE; index++ )
	{
		current_tile = world_map[ index ];

		if(current_tile != 0)
		{
			printf( "BYTE: %d\tVALUE: %d\n", index, current_tile );
		}
	}


	// Peek at certain tiles and report their values.
	printf("\n\n");

	printf("*** VALUES OF INSPECTED TILES ***\n\n");
	current_tile = get_world_map_tile( 32, 32 );
	printf( "VALUE: %d\n", current_tile );
	current_tile = get_world_map_tile( 54, 17 );
	printf( "VALUE: %d\n", current_tile );
	current_tile = get_world_map_tile( 12, 4  );
	printf( "VALUE: %d\n", current_tile );	

	// Compress and report sprite data.
	create_sprite_values();

	printf("\n\n*** SPRITE COMPRESSION REPORT ***\n\n");

	printf("Output: ");
	
	for( index = 0; index < 8; index ++ )
	{
		printf( "%d, ", sprite_compressed[index] );
	}
}

/**
 * Resets all elements of the world map to 0.
 */
void init_world_map()
{
	unsigned char 	x, y;
	int 		pitch;
	int		array_position;

	pitch = 0;

	for( y = 0; y < WORLD_MAP_DIMENSION; y++ )
	{
		y = y + pitch;
 
		for( x = 0; x < WORLD_MAP_DIMENSION; x++  )
		{
			array_position = pitch + x;
			
			world_map[ array_position ] = 0;
		}

		pitch += WORLD_MAP_DIMENSION;
	}
}


/******************************************************************************************
 * GENERAL FUNCTIONS USED IN THIS PROGRAM
 ******************************************************************************************/

/**
 * Get a tile from the world map.
 */
unsigned char get_world_map_tile( unsigned char x, unsigned char y )
{
	int array_position;

	array_position  = y * WORLD_MAP_DIMENSION;
	array_position += x;

	return world_map[ array_position ];
}

/**
 * Set a tile from the world map.
 * 
 * NOTE: Duplicates code from the "get_world_map_tile()" function, but due to memory and
 *       stack limitation on the Spectrum, I'm not sure if a separate function would help.
 */
void set_world_map_tile( unsigned char new_tile_value, unsigned char x, unsigned char y )
{
	int array_position;

	array_position  = y * WORLD_MAP_DIMENSION;
	array_position += x;

	world_map[ array_position ] = new_tile_value;	
}

/**
 * Takes the sprite array and converts its data into a compressed form.
 * So, the first 8 chars of the sprite array will be squeezed into a single char.
 *
 * Once called, the sprite_compressed array will store the result.
 */
void create_sprite_values()
{
	unsigned char 	x, y;
	int		pitch;
	unsigned char	byte_build;
	unsigned char 	bit;

	for( y = 0; y < 8; y++ )
	{
		pitch 		= y * 8;
		byte_build 	= 0;

		for( x = 0; x < 8; x++ )
		{	
			bit = bits_in_byte[ x ];

			if( sprite[ pitch + x ] == 1 )
			{
				byte_build += bit;
			}
		}

		sprite_compressed[y] = byte_build;
	}
}

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Fri Jan 12, 2018 3:18 pm

Update, concerning keyboard input. Having a spot of bother with character cursor location...

Code: Select all

/*********************************************************
 * "mapscroll.c" by S.A Ray (SamusDrake)				 
 *							 
 * This program is a tile-map scrolling demo; displaying
 * only the tiles the view can see on a world map.
 *
 * An example of this would be the world map screen in many 
 * an early japanese 2D rpg.
 *
 * CURRENT: Testing user input...
 *
 *********************************************************
 *
 * Use Q, A, O, P to show UP! DOWN!, LEFT! & RIGHT! on
 * the screen.
 *
 * Press T to quit.
 *
 *********************************************************
 *
 * NOTE: This source file is a work-in-progress, as it is 
 *       a more complex project.  Unlike previous examples,
 *	 the code might be a bit sloppy. 
 *
 * LAST UPDATE: 12th January, 2018.
 * 
 *********************************************************
 *
 * In the target Spectrum model, the 48K, the screen
 * memory map starts and finishes at the following
 * addresses...
 *
 * start:    0x4000	(16384)
 * finish:   0x57FF	(22528)
 *
 * The size of the screen memory map is 6144 bytes long.
 * That does not include the colour memory map.
 *
 *********************************************************
 *			 
 * Spectrum screen resolution: 256 * 192 pixels
 * Back buffer memory usage:  6144 bytes;    
 *
 * Compile with: zcc +zx -lm -lndos -create-app mapscroll.c
 *
 *********************************************************         
 *
 * Written using z88dk.
 *
 * Thank you to the community at the ZX Spectrum 
 * Next forum, and the Speccy community at large.
 *
 *********************************************************/ 

#include <stdio.h>

#define WORLD_MAP_DIMENSION	64
#define WORLD_MAP_ARRAY_SIZE	4096

#define KEY_UP	  'Q'
#define KEY_DOWN  'A'
#define KEY_LEFT  'O'
#define KEY_RIGHT 'P'
#define KEY_QUIT  'T'

void 		demo_control();
void 		obtain_input();
void 		reset_print_cursor();
void 		present_data_information();
void 		init_world_map();
unsigned char 	get_world_map_tile( unsigned char x, unsigned char y );
void 		set_world_map_tile( unsigned char new_tile_value, unsigned char x, unsigned char y );
void		create_sprite_values();

unsigned char running;

unsigned char world_map[ WORLD_MAP_ARRAY_SIZE ];

unsigned char bits_in_byte[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };

// Sprite in its basic form of 64 elements( 8 * 8 pixels )
unsigned char sprite[64]=
{
	1,0,0,0,0,0,0,1,
	0,1,0,0,0,0,1,0,
	0,0,1,0,0,1,0,0,
	0,0,0,1,1,0,0,0,
	0,0,0,1,1,0,0,0,
	0,0,1,0,0,1,0,0,
	0,1,0,0,0,0,1,0,
	1,0,0,0,0,0,0,1
};

// This is the array which will hold the compressed version of the sprite array.
unsigned char sprite_compressed[8];

/******************************************************************************************
 * MAIN AND INITIALIZATION FUNCTIONS
 ******************************************************************************************/


/**
 * MAIN FUNCTION.
 */
main()
{
	running = 1;

	demo_control();
}

/**
 * The main program loop for obtaining keyboard input and 
 * re-rendering if necessary.
 */
void demo_control()
{
	while(running)
	{
		// Get key input
		obtain_input();

		// Add render-code here.
	}
}

/**
 * Supposed to set the text cursor to the top-left of the screen,
 * but doesnt seem to work inconjunction with the printf() function.
 * I'm definitely overlooking something here!
 *
 * Referenced from Daryl Sloan's second youtube assembly video.
 */
void reset_print_cursor()
{
	__asm

		ld 	a, 2
		call 	5633

	__endasm
}

/**
 * Check for which key has been pressed and respond
 *
 * Using the input loop from the z88dk dstar example
 * as a guide.
 *
 * reset_print_cursor() is a work in progress...
 */
void obtain_input()
{
	switch( toupper( getk() ) )
	{
		case KEY_UP:
		{
			clg();
			reset_print_cursor();
			printf("UP!");
			break;
		}

		case KEY_DOWN:
		{
			clg();
			reset_print_cursor();
			printf("DOWN!");
			break;
		}

		case KEY_LEFT:
		{
			clg();
			reset_print_cursor();
			printf("LEFT!");
			break;
		}

		case KEY_RIGHT:
		{
			clg();
			reset_print_cursor();
			printf("RIGHT!");
			break;
		}

		case KEY_QUIT:
		{
			clg();
			running = 0;
			break;
		}
	}
}

/**
 * DISPLAYS WORLD MAP AND SPRITE COMPRESSION DATA.
 */
void present_data_information()
{
	int 		index;
	unsigned char 	current_tile;

	clg();

	init_world_map();

	set_world_map_tile( 128, 32, 32 );
	set_world_map_tile( 57,  54, 17 );
	set_world_map_tile( 234, 12, 4  );

	// Search all the tiles for any that were "set" and 
	// report their values.
	printf("*** LIST OF SET TILES ***\n\n");
	
	for( index = 0; index < WORLD_MAP_ARRAY_SIZE; index++ )
	{
		current_tile = world_map[ index ];

		if(current_tile != 0)
		{
			printf( "BYTE: %d\tVALUE: %d\n", index, current_tile );
		}
	}


	// Peek at certain tiles and report their values.
	printf("\n\n");

	printf("*** VALUES OF INSPECTED TILES ***\n\n");
	current_tile = get_world_map_tile( 32, 32 );
	printf( "VALUE: %d\n", current_tile );
	current_tile = get_world_map_tile( 54, 17 );
	printf( "VALUE: %d\n", current_tile );
	current_tile = get_world_map_tile( 12, 4  );
	printf( "VALUE: %d\n", current_tile );	

	// Compress and report sprite data.
	create_sprite_values();

	printf("\n\n*** SPRITE COMPRESSION REPORT ***\n\n");

	printf("Output: ");
	
	for( index = 0; index < 8; index ++ )
	{
		printf( "%d, ", sprite_compressed[index] );
	}
}

/**
 * Resets all elements of the world map to 0.
 */
void init_world_map()
{
	unsigned char 	x, y;
	int 		pitch;
	int		array_position;

	pitch = 0;

	for( y = 0; y < WORLD_MAP_DIMENSION; y++ )
	{
		y = y + pitch;
 
		for( x = 0; x < WORLD_MAP_DIMENSION; x++  )
		{
			array_position = pitch + x;
			
			world_map[ array_position ] = 0;
		}

		pitch += WORLD_MAP_DIMENSION;
	}
}


/******************************************************************************************
 * GENERAL FUNCTIONS USED IN THIS PROGRAM
 ******************************************************************************************/

/**
 * Get a tile from the world map.
 */
unsigned char get_world_map_tile( unsigned char x, unsigned char y )
{
	int array_position;

	array_position  = y * WORLD_MAP_DIMENSION;
	array_position += x;

	return world_map[ array_position ];
}

/**
 * Set a tile from the world map.
 * 
 * NOTE: Duplicates code from the "get_world_map_tile()" function, but due to memory and
 *       stack limitation on the Spectrum, I'm not sure if a separate function would help.
 */
void set_world_map_tile( unsigned char new_tile_value, unsigned char x, unsigned char y )
{
	int array_position;

	array_position  = y * WORLD_MAP_DIMENSION;
	array_position += x;

	world_map[ array_position ] = new_tile_value;	
}

/**
 * Takes the sprite array and converts its data into a compressed form.
 * So, the first 8 chars of the sprite array will be squeezed into a single char.
 *
 * Once called, the sprite_compressed array will store the result.
 */
void create_sprite_values()
{
	unsigned char 	x, y;
	int		pitch;
	unsigned char	byte_build;
	unsigned char 	bit;

	for( y = 0; y < 8; y++ )
	{
		pitch 		= y * 8;
		byte_build 	= 0;

		for( x = 0; x < 8; x++ )
		{	
			bit = bits_in_byte[ x ];

			if( sprite[ pitch + x ] == 1 )
			{
				byte_build += bit;
			}
		}

		sprite_compressed[y] = byte_build;
	}
}


Previous content of the main function is now placed in its own function in case we want to run it again.

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Sat Jan 27, 2018 10:19 am

Here is an update where you can move a single 8*8 sprite around the screen, as if you were selecting a tile on a map...

Code: Select all

/*********************************************************
 * "mapscroll.c" by S.A Ray (SamusDrake)				 
 *							 
 * This program is a tile-map scrolling demo; displaying
 * only the tiles the view can see on a world map.
 *
 * An example of this would be the world map screen in many 
 * an early japanese 2D rpg.
 *
 * CURRENT: Testing sprite display and performance.
 *
 *********************************************************
 *
 * Use Q, A, O, P to move on-screen cursor sprite.
 *
 * Press T to quit.
 *
 * NOTE: The cursor can move in one direction only. Holding
 * 	 down multiple buttons will result in no movement.
 *
 *********************************************************
 *
 * NOTE: This source file is a work-in-progress, as it is 
 *       a more complex project.  Unlike previous examples,
 *	 the code might be a bit sloppy. 
 *
 * LAST UPDATE: 27th January, 2018.
 * 
 *********************************************************
 *
 * In the target Spectrum model, the 48K, the screen
 * memory map starts and finishes at the following
 * addresses...
 *
 * start:    0x4000	(16384)
 * finish:   0x57FF	(22528)
 *
 * The size of the screen memory map is 6144 bytes long.
 * That does not include the colour memory map.
 *
 *********************************************************
 *			 
 * Spectrum screen resolution: 256 * 192 pixels
 * Back buffer memory usage:  6144 bytes;    
 *
 * Compile with: zcc +zx -lm -lndos -create-app mapscroll.c
 *
 *********************************************************         
 *
 * Written using z88dk.
 *
 * Thank you to the community at the ZX Spectrum 
 * Next forum, and the Speccy community at large.
 *
 *********************************************************/ 

#include <stdio.h>

#define WORLD_MAP_DIMENSION	64
#define WORLD_MAP_ARRAY_SIZE	4096

#define KEY_UP	  'Q'
#define KEY_DOWN  'A'
#define KEY_LEFT  'O'
#define KEY_RIGHT 'P'
#define KEY_QUIT  'T'

#define SIZE_OF_SCREEN_MAP  6144
#define SCREEN_MAP_START    0x4000
#define SCREEN_MAP_END      0x57FF

// Function prototypes
void 			demo_control();
void 			obtain_input();
void 			reset_print_cursor();
void 			present_data_information();
void 			init_world_map();
unsigned char 	get_world_map_tile( unsigned char x, unsigned char y );
void 			set_world_map_tile( unsigned char new_tile_value, unsigned char x, unsigned char y );
void			create_sprite_values();
void 			fill_screen_Y_lookup(); 
void 			fill_screen_line_lookup(); 
void 			init_look_ups(); 
void 			init_back_buffer( unsigned char value ); 
void 			plot_pixel( unsigned char x, unsigned char y );
void 			flip();
void			render_frame();
void 			draw_sprite( unsigned char x, unsigned char y );
unsigned char	getSpritePixel( unsigned char x, unsigned char y );
void 			move_player( int x, int y );
void 			clear_rows( unsigned char start, unsigned char end );

unsigned char 	running;
int			player_x, player_y;
int	      		player_speed;

// World map buffer.
unsigned char world_map[ WORLD_MAP_ARRAY_SIZE ];


// Sprite in its basic form of 64 elements( 8 * 8 pixels )
unsigned char sprite[64]=
{
	1,1,1,0,0,1,1,1,
	1,1,0,0,0,0,1,1,
	1,0,1,0,0,1,0,1,
	0,0,0,1,1,0,0,0,
	0,0,0,1,1,0,0,0,
	1,0,1,0,0,1,0,1,
	1,1,0,0,0,0,1,1,
	1,1,1,0,0,1,1,1
};

// This is the array which will hold the compressed version of the sprite array.
unsigned char 	sprite_compressed[8];

// Look-up tables
int 		lookup_screen_Y[192];
int 		lookup_screen_line[256];
unsigned char	lookup_pixel[8];
unsigned char 	bits_in_byte[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };

// Program buffers
unsigned char 	back_buffer[SIZE_OF_SCREEN_MAP];


/******************************************************************************************
 * MAIN AND INITIALIZATION FUNCTIONS
 ******************************************************************************************/


/**
 * MAIN FUNCTION.
 */
main()
{
	// Initiialise player data.
	player_x = 0;
	player_y = 0;
	player_speed = 8;

	// Initialisations
	init_look_ups();
	init_back_buffer( 0 );
	create_sprite_values();

	render_frame();

	// Begin demo...
	running = 1;

	demo_control();
}

/**
 * The main program loop for obtaining keyboard input and 
 * re-rendering if necessary.
 */
void demo_control()
{
	while( running )
	{
		// Get key input
		obtain_input();
	}
}


/**
 * Check for which key has been pressed and respond
 *
 * Using the input loop from the z88dk dstar example
 * as a guide.
 *
 * reset_print_cursor() is a work in progress...
 */
void obtain_input()
{
	switch( toupper( getk() ) )
	{
		case KEY_UP:
		{
			init_back_buffer( 0 );;
			move_player( 0, -player_speed );
			render_frame();
			break;
		}

		case KEY_DOWN:
		{
			init_back_buffer( 0 );
			move_player( 0, player_speed );
			render_frame();
			break;
		}

		case KEY_LEFT:
		{
			init_back_buffer( 0 );
			move_player( -player_speed, 0 );
			render_frame();
			break;
		}

		case KEY_RIGHT:
		{
			init_back_buffer( 0 );
			move_player( player_speed, 0 );
			render_frame();
			break;
		}

		case KEY_QUIT:
		{
			init_back_buffer( 0 );
			running = 0;
			break;
		}
	}
}

/**
 * Renders the game screen.
 *
 * note: to be called only when a button has been pressed.
 */
void render_frame()
{
	draw_sprite( player_x, player_y );

	flip();
}


/**
 * Displays world map and sprite compression data.
 *
 * NOTE: Not currently used in this demo, but might be useful to keep around...
 */
void present_data_information()
{
	int 			index;
	unsigned char 	current_tile;

	clg();

	init_world_map();

	set_world_map_tile( 128, 32, 32 );
	set_world_map_tile( 57,  54, 17 );
	set_world_map_tile( 234, 12, 4  );

	// Search all the tiles for any that were "set" and 
	// report their values.
	printf("*** LIST OF SET TILES ***\n\n");
	
	for( index = 0; index < WORLD_MAP_ARRAY_SIZE; index++ )
	{
		current_tile = world_map[ index ];

		if(current_tile != 0)
		{
			printf( "BYTE: %d\tVALUE: %d\n", index, current_tile );
		}
	}

	// Peek at certain tiles and report their values.
	printf("\n\n");

	printf("*** VALUES OF INSPECTED TILES ***\n\n");
	current_tile = get_world_map_tile( 32, 32 );
	printf( "VALUE: %d\n", current_tile );
	current_tile = get_world_map_tile( 54, 17 );
	printf( "VALUE: %d\n", current_tile );
	current_tile = get_world_map_tile( 12, 4  );
	printf( "VALUE: %d\n", current_tile );	

	// Compress and report sprite data.
	create_sprite_values();

	printf("\n\n*** SPRITE COMPRESSION REPORT ***\n\n");

	printf("Output: ");
	
	for( index = 0; index < 8; index ++ )
	{
		printf( "%d, ", sprite_compressed[index] );
	}
}

/**
 * Resets all elements of the world map to 0.
 */
void init_world_map()
{
	unsigned char 	x, y;
	int 			pitch;
	int				array_position;

	pitch = 0;

	for( y = 0; y < WORLD_MAP_DIMENSION; y++ )
	{
		y = y + pitch;
 
		for( x = 0; x < WORLD_MAP_DIMENSION; x++  )
		{
			array_position = pitch + x;
			
			world_map[ array_position ] = 0;
		}

		pitch += WORLD_MAP_DIMENSION;
	}
}


/******************************************************************************************
 * GENERAL FUNCTIONS USED IN THIS PROGRAM
 ******************************************************************************************/

/**
 * Get a tile from the world map.
 */
unsigned char get_world_map_tile( unsigned char x, unsigned char y )
{
	int array_position;

	array_position  = y * WORLD_MAP_DIMENSION;
	array_position += x;

	return world_map[ array_position ];
}

/**
 * Set a tile from the world map.
 * 
 * NOTE: Duplicates code from the "get_world_map_tile()" function, but due to memory and
 *       stack limitation on the Spectrum, I'm not sure if a separate function would help.
 */
void set_world_map_tile( unsigned char new_tile_value, unsigned char x, unsigned char y )
{
	int array_position;

	array_position  = y * WORLD_MAP_DIMENSION;
	array_position += x;

	world_map[ array_position ] = new_tile_value;	
}

/**
 * Takes the sprite array and converts its data into a compressed form.
 * So, the first 8 chars of the sprite array will be squeezed into a single char.
 * Same for the remaining 7 blocks of 8.
 *
 * Once called, the sprite_compressed array will store the result.
 */
void create_sprite_values()
{
	unsigned char 	x, y;
	int				pitch;
	unsigned char	byte_build;
	unsigned char 	bit;

	for( y = 0; y < 8; y++ )
	{
		pitch 		= y * 8;
		byte_build 	= 0;

		for( x = 0; x < 8; x++ )
		{	
			bit = bits_in_byte[ x ];

			if( sprite[ pitch + x ] == 1 )
			{
				byte_build += bit;
			}
		}

		sprite_compressed[y] = byte_build;
	}
}


/******************************************************************************************
 * FUNCTIONS FROM PREVIOUS DEMOS TO HELP WITH GRAPHICS.
 ******************************************************************************************/


/**
 * Creates a look-up table to store screen map addresses 
 * corresponding to carteansian coordinates on the Y-axis.
 */
void fill_screen_Y_lookup()
{
	int index;
	int power;
	int result;
	int growth;
	int location;
	int offset;
	int start_of_memory_block;
	int element;

	unsigned char block_loop;
	unsigned char starting_height 	= 0;
	unsigned char height_offset 	= 0;

	for( block_loop = 0; block_loop < 3; block_loop++ )
	{
		growth				= 0;
		start_of_memory_block	= 2048 * block_loop;
		starting_height			= 64   * block_loop;
		height_offset	       += 64;

		for( index = starting_height; index < height_offset; index += 8 )
		{
			for( power = 0; power < 8; power++ )
			{
				location = 256 * power;
				offset	 = 32  * growth;

				result  = location + offset + start_of_memory_block;
				element = index + power;

				lookup_screen_Y[element] = result;	
			}
		
			growth++;
		}
	}
}


/**
 * Fills the x-row look-up table.
 */
void fill_screen_line_lookup()
{
	int 			index;
	unsigned char 	count;
	unsigned char 	current_byte;

	count 			= 0;
	current_byte 	= 0;

	for( index = 0; index < 256; index++ )
	{
		// 1) Store the byte and then bit values
		lookup_screen_line[index] = current_byte << 3;
		lookup_screen_line[index] = lookup_screen_line[index] | count;

		// Perform increments and resets(if necessary)
		count++;

		if( count == 8 )
		{
			count = 0;
			current_byte++;
		}
	}
}


/**
 * Call this function before using x, y and pixel bit look-up tables.
 */
void init_look_ups()
{	
	lookup_pixel[0] = 128;
	lookup_pixel[1] = 64;
	lookup_pixel[2] = 32;
	lookup_pixel[3] = 16;
	lookup_pixel[4] = 8;
	lookup_pixel[5] = 4;
	lookup_pixel[6] = 2;
	lookup_pixel[7] = 1;

	fill_screen_line_lookup();
	fill_screen_Y_lookup();
}


/**
 * Sets all the bytes in the back buffer to the given value
 */
void init_back_buffer( unsigned char value )
{
	memset( back_buffer, value, SIZE_OF_SCREEN_MAP );
}



/**
 * Plots a black pixel to the screen using the given (x,y) coordinates.
 *
 * This function is fine for just the odd pixel here'n'there,
 * but is very slow for blitting large amounts of pixels; eg -
 * a bitmap or sprite.
 *
 * WARNING: The calling code is responsible for ensuring that the 
 * 	    given X, Y coordinates are valid...
 *
 *		x ( 0 - 255 ) display width is 256 pixels
		y ( 0 - 191 ) display height is 192 pixels
 */
void plot_pixel( unsigned char x, unsigned char y )
{
	int 			address;
	unsigned char 	pixel_byte;
	unsigned char 	byte;
	unsigned char 	bit;

	// Extract the horizontal byte
	byte = lookup_screen_line[x] >> 3;

	// Extract the horizontal bit
	bit = lookup_screen_line[x] << 5;
	bit = bit >> 5;

	// Calculate which byte in the back buffer address to write to
	address = lookup_screen_Y[y] + byte;

	// Take byte from the back buffer and manipulate the byte...
	pixel_byte	= back_buffer[address];
	pixel_byte 	= pixel_byte | lookup_pixel[bit];

	// ...now store the manipulated byte back into the back buffer
	back_buffer[address] = pixel_byte;	
}

/**
 * Renders the sprite to the back buffer at the 
 * given coordinates.
 */
void draw_sprite( unsigned char x, unsigned char y )
{
	int 			lx, ly;
	unsigned char 	retByte;

	for( ly = 0; ly < 8; ly++ )
	{
		for( lx = 0; lx < 8; lx++ )
		{
			// The following three lines can be replaced
			// with getSpritePixel(), if you want.
			retByte = sprite_compressed[ly];
			retByte = retByte << lx;
			retByte = retByte >> 7;

			// If the retrieved pixel is "solid" then render
     			// it.
			if(retByte == 1)
			{	
				plot_pixel( x+lx, y+ly );
			}
		}
	}
}

/**
 * Obtains a pixel from this demo's single sprite.
 *
 * NOTE: draw_sprite() can use this function, but is implemented in-function
 *       to eliminate function-calling overhead. 
 */
unsigned char getSpritePixel( unsigned char x, unsigned char y )
{
	unsigned char rowbyte = sprite_compressed[y];

	rowbyte = rowbyte << x;
	rowbyte = rowbyte >> 7;

	return rowbyte;
}


/**
 * Moves the player(the cursor sprite) in four directions.
 * provide a negative value to move it left, or up and
 * a positive value for right and down.
 */ 
void move_player( int x, int y )
{
	player_x += x;
	player_y += y;

	if( player_x < 1 )
		player_x = 1;

	if( (player_x+8) > 255 )
		player_x = 255 - 8;

	if( player_y < 1 )
		player_y = 1;

	if( (player_y+8) > 191 )
		player_y = 191 - 8;
}


/**
 * Copys the contents of the back buffer to the screen memory
 */
void flip()
{
	memcpy( SCREEN_MAP_START, back_buffer, SIZE_OF_SCREEN_MAP );
}

...just be aware that there is some indentation issues - which is a pain as its perfect in the original copy of this source code, but when placed in here it becomes a nightmare to adjust. Everything seems to be on its correct line though.

Not sure when the next update is but bare with me! ^_^

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Thu Feb 01, 2018 7:39 pm

Here is an additional function that draws a line to the back buffer in the previous program, but first we just to add two constants...

Code: Select all


#define TRUE 1
#define FALSE 0

...and finally, the function itself, which I've ported over from my regular Java rendering engine...

Code: Select all

/**
 * Draw a line on the back buffer.
 * Assumes given arguments are within screen resolution of 256*192
 */
void draw_line( int x1, int y1,
		int x2, int y2 )
{
	int 	count;	
	int	mapped;
	int 	x, y;
	int 	lengthX, lengthY;
	int 	negativeDirectionX, negativeDirectionY;
	float 	scaler;
	
	lengthX 		= x2 - x1;
	lengthY 		= y2 - y1;
	negativeDirectionX 	= FALSE;
	negativeDirectionY 	= FALSE;

	if( lengthX < 0 )
	{
		lengthX 		= lengthX * -1;
		negativeDirectionX 	= TRUE;
	}

	if( lengthY < 0 )
	{
		lengthY 		= lengthY * -1;
		negativeDirectionY 	= TRUE;
	}

	if( lengthX >= lengthY )
        {
            	// X-axis dominate
            	for( count = 0; count < lengthX; count++ )
            	{
			scaler = (float)count / (float)lengthX;
                	mapped = (int)( (float)lengthY * scaler );	


			if( negativeDirectionX )
                	{
                	    x = x1 - count;
                	}
                	else
                	{
                	    x = x1 + count;
                	}

                
                	if( negativeDirectionY )
                	{
                	    y = y1 - mapped;
                	}
                	else
                	{
                	    y = y1 + mapped;
                	}

			plot_pixel( x, y );
		}
	}
	else
	{
		for( count = 0; count < lengthY; count++ )
            	{
                	scaler = (float)count / (float)lengthY;
                	mapped = (int) ( (float)lengthX * scaler );
                

                	if( negativeDirectionX )
                	{
                   		x = x1 - mapped;
                	}
                	else
                	{
                    		x = x1 + mapped;
                	}

                
                	if( negativeDirectionY )
                	{
                		y = y1 - count;
                	}
                	else
                	{
                		y = y1 + count;
                	}

			plot_pixel( x, y );
		}
	}
}

Sadly, this code is super-slow. Unless you enjoy 2-minute-delay slide shows, you will not be making Star Wars with it. How they ported the arcade game to the Speccy is just mindboggling. May we all tip our top hats off to those programmers who worked that wonder. They even pulled that off in Assembly language. Oh my god. And here I am pissing about in C, struggling to find decent speed in a single monochrome line.

Sigh. More next week.

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Sat Feb 17, 2018 9:27 am

Updated z88dk on my ubuntu machine today, and it went well save for one thing only.

In the installation instructions for linux, it provides the following instructions...

Code: Select all

cd z88dk
  chmod 777 build.sh
  chmod 777 config.sh
  ./build.sh
...but it is the line...

Code: Select all

	chmod 777 config.sh
...that causes an error - config.sh is not in the z88dk directory. That said, I carried on anyway to build z88dk and I haven't noticed any problems when compiling my latest spectrum project. I take it the instructions are merely out of date and the config.sh file is no longer required?

That aside, I might look at compiling a program for the Next using the ZEsarUX emulator...

User avatar
varmfskii
Posts: 182
Joined: Fri Jun 23, 2017 1:13 pm
Location: Albuquerque, NM USA

Re: First steps into Z88DK...and many more to come!

Post by varmfskii » Sat Feb 17, 2018 3:54 pm

Don't worry about config.sh, you don't need it. The docs are outdated.
Backer #2741 - TS2068, Byte, ZX Evolution

SamusDrake
Posts: 250
Joined: Mon Jun 26, 2017 10:11 pm
Contact:

Re: First steps into Z88DK...and many more to come!

Post by SamusDrake » Sat Feb 17, 2018 9:57 pm

Cheers Varm. ^_^

Post Reply