Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > C64 32 Sprites 8x4 and Gaps
2016-10-16 21:36
wbochar

Registered: May 2002
Posts: 29
C64 32 Sprites 8x4 and Gaps

I have an ASM program that is trying to display 32 Sprites. I get all 32 on the screen as long as there is a 2px width gap between them. They are laid out in a grid (see below) so each line group has the same xpos (set once)

The moment I either make the raster happen earlier (corrupts the sprite) if not I get a horizontal gap between each grouping.

Fussing with the rasterline and Ypos of the sprites is not working.. is this possible?

Notes:

Numbers are sprites slots, Letters are sprite bitmaps in non-stretched mode (21px tall). I have also turned off the top/bottom borders.

AA:0-AB:1-AC:2-AD3-AE4-AF5-AG6-AH7
AI:0-AJ:1-AK:2-AL3-AM4-AN5-AI6-AO7
BA:0-BB:1-BC:2-BD:3-BE4-BF5-BG6-BH7
BI:0-AJ:1-BK:2-BL:3-BM4-BN5-BI6-BO7

Raster IRQ fires at:


BorderTopIRQ:
0         : turn off upper border
          : Set Sprites 0-7 (No Stretch, Enable, X-pos)
          : Update RasterIRQ Line to LogoIRQLine1
LogoIRQLine1:
10        : Set Sprites 0-7 y-position (RasterLine+2)
          : Set Sprites 0-7 bitmaps (AA,AB,AC,AD...)
          : Update RasterIRQ Line to LogoIRQLine1
LogoIRQLine2:
10+(21*1) : Set Sprites 0-7 y-position (RasterLine+2)
          : Set Sprites 0-7 bitmaps (AJ,AK,AL,AM...)
          : Update RasterIRQ Line to LogoIRQLine2
LogoIRQLine3:
10+(21*2) : Set Sprites 0-7 y-position (RasterLine+2)
          : Set Sprites 0-7 bitmaps (BA,BB,BC,BD...)
          : Update RasterIRQ Line to LogoIRQLine3
LogoIRQLine4:
10+(21*3) : Set Sprites 0-7 y-position (RasterLine+2)
          : Set Sprites 0-7 bitmaps (BJ,BK,BL,BM...)
          : Update RasterIRQ Line to BorderBottomIRQ
BorderBottomIRQ:
250       : turn off lower border
          : Update RasterIRQ to the BorderTopIRQ
2016-10-16 21:48
chatGPZ

Registered: Dec 2001
Posts: 11386
you should start with making the Y-pos updates and sprite pointer updates two different things.... Y-pos is totally non critical, you can set the new Y-pos anywhere in the next 20 lines or so after the current Y pos. make this work first, with a static graphic/sprite pointer. it should be very easy :)

then when this works, interleave the sprite pointer updates into your routine. this can be a bit more tricky, as the update happens immediately and takes effect at any time - so you want to push the update to the point when the current sprite has just ended. for large blocks of sprites you'll have trouble doing it 100% correctly, because the badlines come in the way - which means you dont have enough cycles there to update all pointers in time. one common "trick" is to use two videorams then, so you only have to switch $d018 and all sprite pointers change.
2016-10-17 06:41
Bitbreaker

Registered: Oct 2002
Posts: 508
if you do/can not use the $d018 trick and stay away from badlines, you might want to do it like the following to save cycles on sprite pointer changes:

lda #$01
ldx #$fe
sax screen + $3f8    ;00
sta screen + $3f9    ;01
lda #$03
sax screen + $3fa    ;02
sta screen + $3fb    ;03
lda #$05
sax screen + $3fc    ;04
sta screen + $3fd    ;05
lda #$07
sax screen + $3fe    ;06
sta screen + $3ff    ;07
2016-10-17 09:15
Oswald

Registered: Apr 2002
Posts: 5094
what everyone said plus:

if I get it right you only have 4 rows of sprites, if first sprite row starts on a badline it should be possible to do it without any tricks, because the 3 next sprite row will not start on a badline. except you have to make it as fast as possible + you need to fine tune the timing of the writes horizontally

bad lines are first pixel row of a character row, where the cpu is stopped for 40 cycles from the available 63 per raster line. also 8 sprites make the cpu stop for another ~20 cycles, thus you have no cycles left to change the sprite pointers ON a badline. you might start on the prvs line tho as Groepaz says.

this may sound very hi tech, but all you need is to change background color to see where the cpu is on the screen, then some trial and error with nops + lda #sprptr sta scr+3x
2016-10-17 09:52
Fresh

Registered: Jan 2005
Posts: 101
@Bitbreaker: cool trick!! With that code you can have 8 sprites and waste just one $3fx area for pointers. Moreover, LDX can even be put *before* the critical code and you get 40 cycles against 48 of a normal lda+sta approach: that means 4 free cycles (63-19-40) for ie FLD (hence you can avoid idle mode). Thanks for sharing!
2016-10-17 10:42
chatGPZ

Registered: Dec 2001
Posts: 11386
another thing you can do, depending on what you want to achive at the end.... just dont put all your sprites on the same Y position, but for example move down 4 of them 2 lines or so
2016-10-17 11:21
ChristopherJam

Registered: Aug 2004
Posts: 1409
I agree with Oswald that with careful Y positioning you can make the timing of the updates a lot less critical, and agree that starting with the sprites on a badline (rc=0) will work. I'd dispute the reasoning though; starting on badlines is fine, ending sprites on badlines is bad.

The sprite data is fetched starting at the end of the preceding line (hence having to set MOBy to one lower than the raster line you want to display on), so what you really want is to avoid having the *last* lines of each of the first three rows of sprites landing on badlines, as that's when you want to be setting up the pointers for the next row.

Place the first set on a badline, and you have rows starting at rc=0,5,2 and 7 respectively - all good!

Of course, you can make the timing a lot less critical with a little duplicated data, and untethering the sprite pointer update from the physical sprite boundaries. Pretty sure this technique's been mentioned a few times already on these forums, but in short:

- Change sprite definitions every 19 or 20 lines, instead of every 21
- ensure the last few pixel lines of sprite row 0 are copied into the last few lines of sprite row 1
- then the last three or for lines of row 1 copied into row 2, so you can do that switch even earlier etc

Whether that's more or less work than just getting the interrupt timing right depends on the coder. The duplicated data technique is generally more useful when you've got moving sprites or a scrolling background, so you don't know when the badlines are going to occur...
2016-10-17 22:53
wbochar

Registered: May 2002
Posts: 29

Thanks,

Groepaz: Great suggestions, I would have said that to someone else in the same situation.. I wish I'd thought of it. I started simple and moved up.. The Video Ram switcher is a great idea, I have another segment that already uses that for scrolling large segments of text. I'll see if I can mix them together..

Bitbreaker: I have never used SAX, so thanks for giving me a reason to. I tried it out, but in the end the startline and badline combos worked out.

ChristopherJam: Yes, you were right about the badlines and starting points.

So it worked out that....
I set up a static image for all sprites and figured out the positioning.
Then began by replacing the first line with Sprite A0,A1,A2..then did each line after that.
When things started to go wonky with the line I was working on, I would adjust the start line of everything.
Then got the timing right for the last one.. which was on a bad line.. more adjusting the start Y pos and it worked..

It ended up being (SpriteY-2) as the raster line start for the top three sprite lines, then (SpriteY-3) and some padding nops..

Thanks for the tips, you guys really helped.

--Wolf
2016-10-18 14:02
Oswald

Registered: Apr 2002
Posts: 5094
great test gfx there :)
2016-10-18 14:20
Mr. SID

Registered: Jan 2003
Posts: 424
Just one more note here: Sometimes using test sprites like these can mask the problem of sprite pointer changes not happening on exactly the right spot.
In your example the bottoms of all the test sprites are identical, I'd try to avoid that.
2016-10-18 14:26
chatGPZ

Registered: Dec 2001
Posts: 11386
yeah, i usually use some kind of diagonal stripes, then you can spot problems easily
2016-10-18 20:02
Digger

Registered: Mar 2005
Posts: 437
Great thread! How would you go about two 4x4 blocks of unexpanded sprites, with normal graphics underneath (no $d018 trick).

1. Each 4x4 block will have an independent X and Y position
2. The screen is also freely moving in X and Y with $d011/$d016 so badlines will occur on different rasterlines

The trickiest case happens when you have to update all 8 sprite-pointers on a badline when the Y coords of two blocks are aligned – so the thread answers this question.

But how to generate an IRQ handler for that?

Was thinking of a speedcode with injected $d012 values, but then how to handle the critical situation above?

Injected JSR addresses to various update routines (4/8 sprites) would seem to consume too many cycles.
2016-10-18 21:23
algorithm

Registered: May 2002
Posts: 705
Using the duplicated two line or so sprite definition method would ease things a bit (mentioned elsewhere in this thread)
2016-10-18 21:32
Oswald

Registered: Apr 2002
Posts: 5094
digger, you can switch to a totally different multiplex irq for the hard case, which does the 8 spr write on a badline, then have another irq for 8 sprite switch but no badline, etc.

cleaner and faster than selfmod jsr.
2016-10-19 05:56
ChristopherJam

Registered: Aug 2004
Posts: 1409
Two large objects moving freely? Don't think I'd even try to attempt a cycle tuned routine for that one.

Set up first row for each object before the frame starts, then interrupts at y0+16, y0+32, y0+48, y0+64, and similar for y1. (need to sort these, obviously)

Each interrupt updates four sprites, increasing Y by 21, increasing the pointer address to the next row of definitions. Five rows of definitions are needed for each object.

Don't forget to check if the time for the next IRQ has already passed before setting $d012 and exiting, you'll have to fall through to the routine for the other object whenever the Y values are close to each other modulo 16.

It costs an extra 512 bytes of sprite definitions, but this way you've five lines (less sprite DMA and a badline) in which to update eight sprites; should be more than enough.
2016-10-19 20:06
Digger

Registered: Mar 2005
Posts: 437
Some great ideas there, thanks everyone!

@ChristopherJam: I am slowly beginning to understand your idea :) What do you mean by sprite definitions? A lookup table with sprite pointers that can be copied to $03fx?
I could probably use the sprite overlap method too, and shorten sprites to 20 or 19 rows.

I guess I will start experimenting and see how this goes :)
2016-10-20 07:56
Firehawk

Registered: Aug 2011
Posts: 31
You can also exchange some data between the lower lines (where you would get a badline) with the sprite below, then you can change sprite index at some other time than where the sprite ends. If you want a blanket of sprites this would be preferrable - remember that sprite index values can be changed at any time (i.e. each 16 lines, and top sprite being at -4 of first visible line) - that way you never get a sprite index change at badline :-)
2016-10-20 08:22
Oswald

Registered: Apr 2002
Posts: 5094
what if sprite Y-s are shifted by 1 so 8 sprite is never aligned on the same line.

4sprites:

ab
cd

so bd sprites are lower 1 line than ac.
2016-10-20 09:46
ChristopherJam

Registered: Aug 2004
Posts: 1409
@Digger By sprite definitions I just meant the images; I was still talking overlap method. I should probably draw a diagram, or bring code.

@Oswald good point about offsetting. Could even keep y values the same but offset the sprite-pointer change...
2016-12-12 00:48
wbochar

Registered: May 2002
Posts: 29
It's been a while.. Groepaz was right -- my pattern was hiding some errors. The lower line of each sprite was being copied over... I've been beating my head with the keyboard -- so i've given in and decided to post.

It seems I can get 4x4 working without any issues, the moment I move to 4x5 an higher I start getting over lap issues. So two things happen, either I loose the first sprite in even lines or I get to a point where NOP's can't fudge it anymore.

I used Bitbreakers idea for the sprite pointers, which is helping (I spent a while reading about SAX, cool)

I tried to create a really stripped down Multiple IRQ version, I even dropped pushing things to stack and dumping kernal, to see if I could squeeze things out.

But I can't seem to get past this; it must be a mistake in my concept of how to implement this... So here is an example of my sprite / raster irq:

Interupt Setup:

	sei
	lda #$7f
	sta $dc0d
	sta $dd0d
	and $d011 //clear most sign bit vic's raster register
	sta $d011
	lda #0	   //Raster line set
	sta $d012  

	lda #<IRQ_UpperBorder
	sta $fffe
	lda #>IRQ_UpperBorder
	sta $ffff
  
	lda #%00000001
	sta $d01a
	
	lda #$35 //Kill Kernal
	sta $01

        cli


IRQ_UpperBorder:
	
//	inc $d021

	lda ScreenControlRegister
	ora #%00001000
	sta ScreenControlRegister


	.for (var i = SpriteCount; i >= 0; i--) 
	{
		lda #WHITE
		sta sprites.colors + i
	}

	lda #BLUE
	sta sprites.color1
	lda #LIGHT_BLUE
	sta sprites.color2

	lda #SpriteEnable
	sta sprites.enable_bits

	//All rightside sprites with x>255 need this set
	lda #%00000000
	sta sprites.position_x_high_bits
	sta sprites.horizontal_stretch_bits
	sta sprites.vertical_stretch_bits


	// Set Horizontal Positions for Logo Sprites (set once)
	.for (var i = SpriteCount; i >= 0; i--) 
	{
		ldx #(BorderWidth)+24*i
		stx sprites.positions + 2 * i + 0
	}


	lda #LogoStartY-1	//Raster line set
	sta $d012	

	lda #<IRQ_Logo1
	sta $fffe
	lda #>IRQ_Logo1
	sta $ffff	

	asl $d019 // Ack the VIC INT

	rti



IRQ_Logo1:

        //inc $d021
	
       // About 15 NOPS here

	lda #(SpriteBank+8+1)
	ldx #254
	sax sprites.pointers+0    //00
	sta sprites.pointers+1    //01
	lda #(SpriteBank+8+3)
	sax sprites.pointers+2    //02
	sta sprites.pointers+3    //03
	lda #(SpriteBank+8+5)
	sax sprites.pointers+4    //04
	sta sprites.pointers+5    //05
	lda #(SpriteBank+8+7)
	sax sprites.pointers+6    //06
	sta sprites.pointers+7    //07

	lda #LogoStartY
	.for (var i = SpriteCount; i >= 0; i--) 
	{
		sta sprites.positions + 2 * i + 1
	}

	lda #LogoStartY + (SpriteHeight * 1)-1	//Raster line set
	sta $d012	
	lda #<IRQ_Logo2
	sta $fffe
	lda #>IRQ_Logo2
	sta $ffff	

	asl $d019 //	Ack the VIC INT
	rti

... next Logo2, 3,4 then the bottom border open irq..
2016-12-16 04:29
wbochar

Registered: May 2002
Posts: 29
Ok, so setting the y coordinates before the pointers actually works better.

I got it working, I'll post my example, when its closer to 100%
2016-12-16 06:35
Oswald

Registered: Apr 2002
Posts: 5094
you can set Y coord anywhere BEFORE your sprites start. even during the display of the previous sprite row.
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Mike
Walt/Bonzai
MWR/Visdom
St0rmfr0nt/Quantum
Case/Padua
Trap/Bonzai
.jetan/AI-supported ..
Airwolf/F4CG
B.A./QUANTUM
Titus/Rabenauge
Paulko64
Alakran_64
grasstust/Hoaxers
Guests online: 136
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.6)
5 Edge of Disgrace  (9.6)
6 What Is The Matrix 2  (9.6)
7 The Demo Coder  (9.6)
8 Uncensored  (9.6)
9 Comaland 100%  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 No Listen  (9.6)
3 Cubic Dream  (9.6)
4 Party Elk 2  (9.6)
5 Copper Booze  (9.6)
6 Dawnfall V1.1  (9.5)
7 Rainbow Connection  (9.5)
8 Onscreen 5k  (9.5)
9 Morph  (9.5)
10 Libertongo  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Triad  (9.3)
5 Censor Design  (9.3)
Top Organizers
1 Burglar  (9.9)
2 Sixx  (9.8)
3 hedning  (9.7)
4 Irata  (9.7)
5 Tim  (9.7)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.076 sec.