SP1 init flag SP1_IFLAG_MAKE_ROTTBL?

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
thricenightly
Member
Posts: 28
Joined: Thu Jun 01, 2017 5:46 pm

SP1 init flag SP1_IFLAG_MAKE_ROTTBL?

Post by thricenightly »

What does the SP1 SP1_IFLAG_MAKE_ROTTBL initialisation flag do? Makes a rotation table, obviously, but what does that mean? I couldn't work out from the code what it actually does. I deduced it's used in getting pixel positioning for sprites, which leads me to guess that it contains a cache of rotated sprite data? But since it's a fixed size I'm not sure that's right.

While I'm at it, there's two other initialisation flags: SP1_IFLAG_OVERWRITE_TILES and SP1_IFLAG_OVERWRITE_DFILE. I couldn't work out the first one. It doesn't seem to do anything in my example programs, so it must be related to stuff I've not played with yet. The overwrite dfile one appears to magically turn off writes to the Spectrum's display file. Since such a feature in itself would be rather pointless I'm guessing it must do something a bit more subtle than that. :)

Every SP1 example in the Z88DK source distribution supplies all 3 flags to the sp1_initialize() function. I'm wondering why they're offered as flags if they're always required?
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

> Every SP1 example in the Z88DK source distribution supplies all 3 flags to the sp1_initialize() function. I'm wondering why they're offered as flags if they're always required?

The sp1_initialize function is initializing all of sp1's data structures. If any of the flags are not present, then that part of the data structures will not be initialized. Why you might want to do that I will describe below. The memory map sp1 uses (and therefore where these data structures are) is defined in a config file: https://github.com/z88dk/z88dk/blob/mas ... sp1.m4#L24

SP1_IFLAG_MAKE_ROTTBL causes the rotation tables to be generated, which by default are located at address 0xf000 and above (see the config file above). When a sprite is drawn on screen at pixel precision, the image has to be bit shifted to the right from 0-7 pixels. The sprite draw functions use a look up table to do this and that's what these rotation tables are - a look up table. So there's one look up table for rotating the image right one pixel, another for rotating right two pixels, etc ... up to 7 pixels. Maybe you only place sprites on even horizontal pixel coordinates. Then you only need the rotation tables for 1,3,5,7 shifts. Since each table occupies 512 bytes, you save 512*3 = 1536 bytes by doing this. If you supply the rotation tables with your own data in the positions of 2,4,6 by loading it from tape then you don't want sp1_intiialize to build the rotation tables in memory and wipe out your data. Maybe you don't want sp1 to do any horizontal rotation at all. For example, if your sprites use the "*NR" draw functions ( https://github.com/z88dk/z88dk/blob/mas ... sp1.h#L163 ) then the sprite image will not rotate and the rotation tables are not used at all. If you move a *NR sprite right one pixel at a time, it will appear not to move for 0-7 pixel offset, until the sprite moves 8 pixels to the right when the sprite will suddenly move right one character. You can use this in combination with pre-shifted sprite images to do pre-shifted sprites by changing the graphics pointer depending on the current horizontal rotation. So if you don't use the rotation tables at all, you don't want sp1 to build them in memory, possibly overwriting something else you place there. If you don't want to worry about anything and be able to place a sprite at any horizontal pixel position, then the rotation tables have to be there.

If you want to see how the rotation table is used to draw the sprite graphics you can have a look at the SP1_DRAW_OR1 draw function. This one ORs the sprite image into the display and assumes the sprite is 1-byte type (ie graphics no mask in the definition). A little above this point ( https://github.com/z88dk/z88dk/blob/mas ... R1.asm#L45 ) the draw function has determined the shift is not zero (if it is, it jumps to a faster no-shift draw function). At the point shown on line 45, H points at the msb of the rotation table address being used (different depending on shift 1-7). L is loaded with the graphic to shift and a read of the HL address returns the shifted graphic. When you shift a byte right, graphics comes in from the left too. H+1 points at the table used to find out what portion of the graphic from the left shifts into the byte. DE is the pointer to graphics for the current 8-byte char and IX points at graphics defining the sprite char to the left of this one.

SP1_IFLAG_OVERWRITE_TILES causes sp1 to map all tile codes 0-255 to the built in spectrum character set in rom. Remember that a background tile can hold either an ascii code ("tile code") if it's < 256 or a memory address. When the character square is drawn, the background tile code is looked up. If it's > 256, it's taken as a memory address and 8-bytes of graphics data will be copied from there to make the background. If the tile code is < 256, it's treated like an ascii code, eg letter "A". This ascii code is looked up in the SP1V_TILEARRAY ( https://github.com/z88dk/z88dk/blob/mas ... sp1.m4#L22 ). This array is 512 bytes, giving a two byte address for each code 0-255. When letter "A" is stored as background tile, the address at position SP1V_TILEARRAY[65] is used to copy 8-bytes from to the background. The SP1_IFLAG_OVERWRITE_TILES initialization makes sure that the rom character set is pointed to by SP1V_TILEARRAY so that printing an "A" to the background causes an "A" to be drawn on screen. If this flag is not supplied, then the initialization function will only overwrite tile entries that are 0. This allows you to load from tape a tile array that is already set up to point at your own background graphics.

SP1_IFLAG_OVERWRITE_DFILE causes the initialization to write the "screen" members of the struct sp1_updates ( https://github.com/z88dk/z88dk/blob/mas ... /sp1.h#L52 ). Remember in the previous post, sp1 sets up a logical coordinate space that maps onto a rectangular array of struct sp1_update. When you print or move sprites using the sp1 functions, it's mapping 0-31,0-23 char coords to this array of struct sp1_update. But where those struct sp1_updates are drawn on screen is controlled by the "screen" member, which is the screen address of the top of a character on screen. So you can change the shape of the rectangular sp1_update array to something else on screen :- a star, exploded rectangle with gaps between them, etc. But the SP1_IFLAG_OVERWRITE_DFILE option initializes the screen members to what is expected - the rectangular 32x24 array of sp1_updates is mapped to the 32x24 rectangle on screen so that things draw where you expect. Maybe you've loaded from tape a custom screen configuration - then you would not want the initialization function to change your custom screen addresses.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

I can't edit the above so some errata here:

The rotation table is placed at 0xf000 in the config file but that address would correspond to a 512-byte table for 0-pixel shift, which is not needed. So the occupied portion of the rotation tables actually start with pixel shift 1 which is 512 bytes later at 0xf200.

"Maybe you only place sprites on even horizontal pixel coordinates. Then you only need the rotation tables for 1,3,5,7 shifts."

Of course, if you only place sprites on even hor pixel coords, then you only need the rotation tables for 2,4,6 shifts which means you can reclaim the memory for pixel shifts 1,3,5,7 amounting to 512*4 = 2048 bytes reclaimed.
Post Reply