How well can Metal Slug backgrounds be recreated with tiles?

Discussion of development of software for any "obsolete" computer or video game system. See the WSdev wiki and ObscureDev wiki for more information on certain platforms.
93143
Posts: 1715
Joined: Fri Jul 04, 2014 9:31 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by 93143 »

psycopathicteen wrote:If you figure out how many palettes or tiles you need before you do the dynamic animation routine, the dynamic animation routine can work around whatever DMA time is left.
Sounds good.

I just remembered that Metal Slug, if it remains at 30 fps, only requires OAM to be updated every other frame. That might leave some extra room even if CGRAM has to be updated every frame (which may not be necessary; it may be possible to reset any changed BG palettes with HDMA before the end of the frame, which would make CGRAM updates fairly rare if sprite palettes were harmonized rather than rewritten with HDMA).
psycopathicteen wrote:I almost forgot, you can block move 5kB of data together to speed up DMA. Although block moving could be kind've slow, unless you time DMA around HDMA.
Yeah, I'm not sure I like the idea of trying to manually work around the DMA crash bug. And while I can't seem to track down any information on how the S-DD1 is addressed by the SNES, I imagine it uses a fixed source address for decompressed data, in which case you wouldn't be able to use block move anyway. An unrolled loop would work, but if the data source is one byte wide, you can't do an unrolled loop faster than block move unless your target is in the same page as the source, and isn't 5 KB of block move 3/4 of your active CPU time? Slow indeed.

Considering how scripted the game is, I'm wondering if a partly scheduled OBJ VRAM partitioning might make some sense. It sounds like you're dealing with very small chunks, which means a lot of overhead. But if you could use somewhat constant-size slots for certain objects, you could optionally use just a few transfers, or even just one, to load such an object. Any extra data required for an unusually large animation frame could be spilled to the general-purpose dynamic sprite area. This might be useful for maximizing bandwidth, particularly if the S-DD1 requires a bit more setup than plain ROM. Transferring a 70x80 explosion in 128-byte chunks seems unnecessarily fiddly...

Maybe it could be possible to have a simple defragmentation algorithm that would rearrange VRAM to carve object slots out of dynamic sprite areas as desired during lulls in the action, by moving miscellaneous active sprites elsewhere to clear the slot. This could allow object slots to be reversibly split into general-purpose sprite slots if necessary. Any object corresponding to a slot type with no free instances could simply go in as individual sprites, so if you fail to clear a slot in time you just burn a bit more VBlank on the object rather than glitching out or missing important object appearances or state change cues.

Am I making any sense? I kinda wasn't paying much attention during the dynamic animation engine discussions, because I don't think I need one for the game I'm working on...


...It's too bad the SNES can only display black during forced blank. Big explosions like shotgun blasts or the Slug's shells blank the screen white for a couple of frames, which could allow you to comfortably catch up with VRAM DMA if you could do VRAM DMA during a white screen. Though it now occurs to me that if you could force blank with HDMA and get VRAM to open up during HBlank, you could transfer a good bit of extra data with HDMA because a white screen doesn't need to display any sprites. Hmm... maybe such explosions are too rare and unpredictable to help much? At least you could clear a slot for the explosion graphic...
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by psycopathicteen »

I think that would be possible. I could search for as many free slots in a row, and occasionally defrag whenever there is free DMA and VRAM left over.
93143
Posts: 1715
Joined: Fri Jul 04, 2014 9:31 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by 93143 »

Bringing the threads of conversation together a bit: how much CPU time does your method take? Any idea how much this sort of thing would add?

...

Looking at the backgrounds for Mission 1, it seems that the use of colour is fairly modest; large areas could be done with no more than a single palette. However, it has become evident to me that there's a lot of checkerboard dither. This would have to be pretty carefully dealt with if one were to attempt to rescale the graphics horizontally. It may be possible to partially automate it...

I wonder if 8x8 attribute granularity (to partly make up for unaligned palettes in rescaled BG graphics) is worth the extra 2-3 KB of VRAM for the map data... my first instinct is that it's not.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: How well can Metal Slug backgrounds be recreated with ti

Post by Drew Sebastino »

I'm pretty sure it's a hypothetical at this point - maybe a team will come together around it someday, but I at least am certainly too busy right now. In any case I imagine Espozo would want to be involved; he started learning SNES dev with the idea of making this port himself.
Yeah, I would certainly be up for helping anyone if they were to attempt this. I've found out that I don't have near the perseverance to do something like this myself; I haven't programmed for the SNES at all since before the beginning of the year. Well, I found I'm never getting an Irem M92 with how prohibitively expensive they have become, so all my projects involving that are dead, so I have one less thing to distract myself with.
Looking at the backgrounds for Mission 1, it seems that the use of colour is fairly modest; large areas could be done with no more than a single palette.
You'd be surprised though; I remember using PCX2SNES's limited screen tool and finding something like an average of six background palettes. The thing is, a lot of the palettes are identical except for five or so unique colors. Hypothetical or not, I still think you're insane for suggesting rescalling all the graphics. :lol:
93143
Posts: 1715
Joined: Fri Jul 04, 2014 9:31 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by 93143 »

More insane than trying to port Metal Slug to the SNES in the first place? It's not like the graphics would have to be redrawn from scratch. With the proper tools up and running, the sprite graphics would just be a matter of light manual touch-ups. Backgrounds might be a bit more involved (they look really good even with fairly primitive rescaling, but you'd have to fiddle with palettes and checkerboard dither a bit), but it still doesn't seem out of proportion. Maybe because I haven't tried it seriously yet...

I really do think aspect ratio is important. Not so much the exact physical aspect ratio (which is difficult to figure out), but the size of the screen in game terms. For the port to be accurate, the physical aspect ratio should be about right, and you should be able to see the same amount of stuff, including BGs, and each element of the stuff you can see should take up the same fraction of the viewable area as it does in the Neo Geo version. This implies a scaling factor of 256/304 for all graphics (which actually implies a 67x80 large explosion; I don't believe I've mentioned that particular number yet).

Unless you trim the sides of the screen, but my understanding is that the Neo Geo's 320-dot active area was wider than standard, with the 304-dot area being pretty close to 4:3, so trimming the sides would be further from the physical aspect ratio and thus not desirable. On the other hand, if you trimmed the sides you might be able to get away with using just one tilemap per layer without having to use 16x16 tiles, which would give you 8x8 palette granularity, and you'd be able to get the full 20% size reduction for graphics... but the visual aspect ratio would be a bit off, and the resolution would be even lower... also, with 8x8 tiles you wouldn't be able to pack two horizontally-scrolling BGs into one tilemap... not to mention that you'd be perpetually tying up one window mask, leaving just one for anything else you might want to do...

You don't want to be getting shot from offscreen. Nobody likes that. Have you played the Mario Advance games? The smaller screen size does have a substantial effect; the gameplay suffers, and the gamefeel suffers. It's a constant reminder (along with the bad audio and sore hands) that what you're playing is a crunched-down portable version of the actual game.

Isn't the goal to produce the best possible port of Metal Slug? If it takes more work to get better accuracy, so be it. You gave up on rescaling when you were planning to actually do the whole thing yourself. With a team, there'd ideally be at least one person who'd rather spend time massaging pixel art than programming slope physics, so it could happen in parallel. And if it is just a hypothetical, like my port of BotW to the N64, then there's no reason to hold back because practicality isn't a consideration; clearly rescaling Metal Slug's graphics is not beyond human ability, because generating them from scratch wasn't.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: How well can Metal Slug backgrounds be recreated with ti

Post by tepples »

One practical problem with a team is feeding and housing your team for the duration of development. This ultimately ends up leading to a requirement to find an agent for your team to negotiate with SNK.
User avatar
rainwarrior
Posts: 8731
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: How well can Metal Slug backgrounds be recreated with ti

Post by rainwarrior »

Well, a port of Metal Slug to the SNES probably would have had at least a million dollar development budget. Whether or not the graphics could theoretically be ported without sacrifice wouldn't have been an important question for such an endeavour, though. They would have altered the game to be practical enough to finish the project.

It's not really fair to compare to a commercial project, though. This is not a sane commercial undertaking. If you do it you'll do it because you're really interested in meeting this particular challenge. I don't think a lack of licensing from SNK is going to stop you.
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by psycopathicteen »

93143 wrote:Bringing the threads of conversation together a bit: how much CPU time does your method take? Any idea how much this sort of thing would add?
The last time I tested it, it was about 20 to 30 scanlines in the worst case scenario. However I made a bunch of tweeks to it since because it was spagetti code.
93143
Posts: 1715
Joined: Fri Jul 04, 2014 9:31 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by 93143 »

rainwarrior wrote:If you do it you'll do it because you're really interested in meeting this particular challenge. I don't think a lack of licensing from SNK is going to stop you.
Yeah, my idea of a "team" was less a bunch of guys in an office pulling a full-time salary while subsisting on pizza and Red Bull, and more a few like-minded hobbyists working in their spare time and somehow managing to harmoniously divide up the task over the internet. No schedule, no budget.

I'm not sure how demoscene teams manage themselves, but I'm pretty sure they don't pull full-time salaries either...
psycopathicteen wrote:The last time I tested it, it was about 20 to 30 scanlines in the worst case scenario.
Not bad.

So I guess we're hoping that the original game was at least twice as inefficient as it could have been, ideally three times - given the difference between Metal Slug 2 and Metal Slug X, there's clearly some room for improvement...
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by psycopathicteen »

The routine is still pretty long. This is how it looked a several months ago, viewtopic.php?f=12&t=10957&start=255 and I've been trying to squeeze the code down with macros so that it's less intimidating. But, I've also added a "single 32x32 sprite" and "single 16x16 sprite" mode so that single sprite objects don't need large data tables. In order to shrink data, I had to use more code.

Code: Select all

animation:
-;
jsr do_animation
lda {next_slot}
bne -
lda {active_slot_pointer}
cmp {last_object_to_dma}
beq +
-;
jsr do_animation
lda {next_slot}
cmp {last_object_to_dma}
bne -
+;
rts

do_animation:
tcd
ldy {metasprite_request}
bne +				//no animation, if "metasprite_request" is blank
jsr clear_vram_slot
stz {frame_id}
rts
+;
lda {animation_update}		//sprite is animated if "metapsprite" is different from
bne +				//"metasprite_request" or "animation_update" is set
rts
+;
lda $000c,y
sta {vram_size}
clc
adc {total_dma_legnth}		//check if there is enough DMA time for sprite
cmp #$0081
bcc ++
lda {first_object_to_dma}
bne +
tdc
sta {first_object_to_dma}
+;
rts
+;
jsr clear_vram_slot		//clear previous animation frame
lda #$0002
trb {object_traits}
cmp {animation_update}		//if "animation_update" is 2, then frame is rotated 180 degrees
bne +
tsb {object_traits}
+;
stz {animation_update}
ldy {metasprite_request}
lda $000e,y
clc
adc {animation_index}
inc #2
sta {frame_id}
tax
lda.w {animation_copies},x
inc
sta.w {animation_copies},x
dec
beq +				//if animation_copies is not 0, then no further processing is needed
rts
+;
ldx #$ffff
lda $0008,y
sta {temp2}			//"temp2" is ROM bank
bpl +
jmp single_sprite
+;
cmp #$4000
bcc +
jmp single_small_sprite
+;

lda $000a,y			//find the ROM address of sprite graphics
asl #5				//ROM address = metasprite ROM address + (animation frame)*(metasprite ROM size)
sta {vram_width}
sep #$20
lda {animation_index}
lsr
sta $4202
lda $000c,y
sta $4203
rep #$20
lda $4216
asl #5
adc $0006,y
sta {temp3}			//"temp3" is ROM address

lda $0010,y
bpl +				//if $0010,y is $7fff or less, it is the metasprite data itself
tya				//if $0010,y is $8000 or more, it is the address pointing to metasprite data
clc
adc {animation_index}
tax
ldy $0010,x
+;
phd
lda #$0000
tcd
ldx #$ffff
-;
	lda $0010,y
	bne +
	jmp invalid_chr
	+;
	sty.b {temp5}
	lda $0012,y
	sta.b {temp_x}
	lda $0011,y
	and #$0070
	lsr #4
	sta.b {temp8}			//"temp8" counts down the horizontal sprite run
	lda $0018,y
	xba
	lsr #2
	adc.b {temp3}
-;
		sta.b {temp}				//"temp" is the ROM address of the sprite being added
		sta.b {temp9}				//"temp9" is the ROM address of the top sprite in a vertical run
		lda $0014,y
		sta.b {temp_y}
		lda $0011,y
		and #$000f
		sta.b {temp7}			//"temp7" counts down the vertical sprite run
		jmp find_vram_slot
find_vram_slot_done:
		ldy.b {temp5}			//this puts all the "OAM" information
		ora $0016,y
		sta {sprite_attributes},x
		lda.b {temp_y}
		sta {sprite_y},x
		clc
		adc.b {temp10}
		sta.b {temp_y}
		lda.b {temp_x}
		sta {sprite_x},x

		dec.b {temp7}			//decreases "temp 7" until all sprites
		bpl find_vram_slot		//in the vertical run are put on linked list
		dec.b {temp8}			//decreases "temp 8" until all sprites
		bmi +				//in the horizontal run are put on linked list
		clc
		adc.b {temp10}
		sta.b {temp_x}
		lda.b {temp10}
		asl #2
		adc.b {temp9}
		jmp -
+;
	stx.b {temp6}
	tya
	clc
	adc #$000a
	tay
	jmp --

macro find_slot(stack_index,stack,label) {
ldy {stack_index}
dey
dey
bmi {label}
txa
ldx {stack}-$a00000,y
sty {stack_index}
sta {next_sprite},x		//adds slot to linked list
lda x16_lut,x
ora #$4000
ldy {dma_updates}
clc
}

macro add_and_store_2x(a,b) {
sta {b},y
adc {a}
sta {b}+8,y
}

macro add_and_store_4x(a,b) {
add_and_store_2x({a},{b})
adc {a}
add_and_store_2x({a},{b}+16)
}

small_slot:			//this finds 16x16 VRAM slot
find_slot({small_slot_stack_index},{small_slot_stack},invalid_chr)
add_and_store_2x(#$0100,{dma_destination})
lda.b {temp}
add_and_store_2x({vram_width},{dma_address})
adc {vram_width}
sta.b {temp}
lda.b {temp2}
ora #$4000
sta {dma_bank},y
sta {dma_bank}+8,y
stz.b {temp4}
stz.w {sprite_size},x
lda #$0010
jmp +

invalid_chr:
	pld
done_with_animation_routine:
	txa
	ldx {frame_id}
	sta.w {animation_chr},x
	lda {vram_size}
	clc
	adc {total_dma_legnth}
	sta {total_dma_legnth}
	rts				//this is where the game exits the routine

find_vram_slot:
lda $0010,y
and #$0003
dec
beq small_slot
cmp #$0001
beq large_slot
repeat_slot:			//this finds repeat slots
ldy {repeat_slot_stack_index}
dey
dey
bmi invalid_chr
txa
ldx {repeat_slot_stack}-$a00000,y
sty {repeat_slot_stack_index}
sta {next_sprite},x		//puts it on linked list
lda.b {temp4}
ora #$0002
sta {sprite_size},x
lda.b {temp6}
jmp find_vram_slot_done

large_slot:			//finds open 32x32 VRAM slot
find_slot({large_slot_stack_index},{large_slot_stack},invalid_chr)
add_and_store_4x(#$0100,{dma_destination})
lda.b {temp}
add_and_store_4x({vram_width},{dma_address})
adc {vram_width}
sta.b {temp}
lda.b {temp2}
ora #$8000
sta {dma_bank},y
sta {dma_bank}+8,y
sta {dma_bank}+16,y
sta {dma_bank}+24,y
lda #$0001
sta.b {temp4}
sta {sprite_size},x
lda #$0020
+;
sta.b {temp10}
clc
adc.b {dma_updates}
sta.b {dma_updates}
txa
jmp find_vram_slot_done

x16_lut:
dw $0000,$0020,$0040,$0060,$0080,$00a0,$00c0,$00e0,$0110,$0120,$0140,$0160,$0180,$01a0,$01c0,$01e0
dw $0200,$0220,$0240,$0260,$0280,$02a0,$02c0,$02e0,$0310,$0320,$0340,$0360,$0380,$03a0,$03c0,$03e0
dw $0400,$0420,$0440,$0460,$0480,$04a0,$04c0,$04e0,$0510,$0520,$0540,$0560,$0580,$05a0,$05c0,$05e0
dw $0600,$0620,$0640,$0660,$0680,$06a0,$06c0,$06e0,$0710,$0720,$0740,$0760,$0780,$07a0,$07c0,$07e0
dw $0800,$0820,$0840,$0860,$0880,$08a0,$08c0,$08e0,$0910,$0920,$0940,$0960,$0980,$09a0,$09c0,$09e0
dw $0a00,$0a20,$0a40,$0a60,$0a80,$0aa0,$0ac0,$0ae0,$0b10,$0b20,$0b40,$0b60,$0b80,$0ba0,$0bc0,$0be0
dw $0c00,$0c20,$0c40,$0c60,$0c80,$0ca0,$0cc0,$0ce0,$0d10,$0d20,$0d40,$0d60,$0d80,$0da0,$0dc0,$0de0
dw $0e00,$0e20,$0e40,$0e60,$0e80,$0ea0,$0ec0,$0ee0,$0f10,$0f20,$0f40,$0f60,$0f80,$0fa0,$0fc0,$0fe0
dw $1000,$1020,$1040,$1060,$1080,$10a0,$10c0,$10e0,$1110,$1120,$1140,$1160,$1180,$11a0,$11c0,$11e0
dw $1200,$1220,$1240,$1260,$1280,$12a0,$12c0,$12e0,$1310,$1320,$1340,$1360,$1380,$13a0,$13c0,$13e0
dw $1400,$1420,$1440,$1460,$1480,$14a0,$14c0,$14e0,$1510,$1520,$1540,$1560,$1580,$15a0,$15c0,$15e0
dw $1600,$1620,$1640,$1660,$1680,$16a0,$16c0,$16e0,$1710,$1720,$1740,$1760,$1780,$17a0,$17c0,$17e0
dw $1800,$1820,$1840,$1860,$1880,$18a0,$18c0,$18e0,$1910,$1920,$1940,$1960,$1980,$19a0,$19c0,$19e0
dw $1a00,$1a20,$1a40,$1a60,$1a80,$1aa0,$1ac0,$1ae0,$1b10,$1b20,$1b40,$1b60,$1b80,$1ba0,$1bc0,$1be0
dw $1c00,$1c20,$1c40,$1c60,$1c80,$1ca0,$1cc0,$1ce0,$1d10,$1d20,$1d40,$1d60,$1d80,$1da0,$1dc0,$1de0
dw $1e00,$1e20,$1e40,$1e60,$1e80,$1ea0,$1ec0,$1ee0,$1f10,$1f20,$1f40,$1f60,$1f80,$1fa0,$1fc0,$1fe0

macro clear_slot(stack_index,stack) {
ldx {stack_index}
sta.w {stack},x
inx
inx
stx {stack_index}
lda {next_sprite}-$a00000,y
cmp #$ffff
bne -
rts
}

-;
rts
clear_vram_slot:	//this routine clears the VRAM slots of the previous animation frame
ldx {frame_id}
beq -
lda.w {animation_copies},x
beq -
dec
sta.w {animation_copies},x
bne -
lda.w {animation_chr},x
cmp #$ffff
beq -
-;
tay
ldx {sprite_size}-$a00000,y
beq clear_small_slot
dex
beq clear_large_slot
clear_slot({repeat_slot_stack_index},{repeat_slot_stack})
clear_small_slot:
clear_slot({small_slot_stack_index},{small_slot_stack})
clear_large_slot:
clear_slot({large_slot_stack_index},{large_slot_stack})

//////////////////////////////////////////////////////////////////////////////////
sram_bank_crossing:
lda {animation_index}
xba
and #$ff00
-;
cmp #$2000
bcc +
sbc #$2000
inc {temp2}
clc
bra -

single_sprite:
lda $0002,y
bmi sram_bank_crossing
lda {animation_index}
xba
and #$ff00
clc
+;
adc $0006,y
sta {temp3}			//"temp3" is ROM address
lda $0010,y
sta {temp5}
find_slot({large_slot_stack_index},{large_slot_stack},invalid_single_chr)
add_and_store_4x(#$0100,{dma_destination})
lda {temp3}
add_and_store_4x(#$0080,{dma_address})
lda {temp2}
sta {dma_bank},y
sta {dma_bank}+8,y
sta {dma_bank}+16,y
sta {dma_bank}+24,y
tya
clc
adc #$0020
sta {dma_updates}
lda #$0001
sta {sprite_size},x
lda #$fff0
-;
sta {sprite_y},x
sta {sprite_x},x
txa
ora {temp5}
sta {sprite_attributes},x
invalid_single_chr:
jmp done_with_animation_routine

single_small_sprite:
lda {animation_index}
xba
and #$ff00
lsr #2
clc
adc $0006,y
sta {temp3}			//"temp3" is ROM address
lda $0010,y
sta {temp5}			//finds open 32x32 VRAM slot
find_slot({small_slot_stack_index},{small_slot_stack},invalid_single_chr)
add_and_store_2x(#$0100,{dma_destination})
lda {temp3}
add_and_store_2x(#$0040,{dma_address})
lda {temp2}
sta {dma_bank},y
sta {dma_bank}+8,y
tya
clc
adc #$0010
sta {dma_updates}
stz.w {sprite_size},x
lda #$fff8
bra -
[/size]
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: How well can Metal Slug backgrounds be recreated with ti

Post by Drew Sebastino »

Only 30 scanlines tops for finding vram for objects? If I'm interpreting that right, wow... You've already added so many features to your game engine that I don't think I should bother finishing mine. :lol: I forgot, do you use ca65?
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by psycopathicteen »

Just so you know, $a0 is now my default bank, because it is a mirror of bank $80, but with 8kB of SRAM. I did this to avoid register juggling.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: How well can Metal Slug backgrounds be recreated with ti

Post by Drew Sebastino »

Oh, so it's pretty much always 3.56MHz; I know you're a great programmer, but less than 30 lines for that much work seemed insane.

I had Metal Slug in mind when designing it, but that dynamic palette changing idea could come in handy for just about any game with a fair level of verticality; I've been thinking about 4 player games on the SNES and how the players already eat up half of the sprite palettes.
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: How well can Metal Slug backgrounds be recreated with ti

Post by lidnariq »

Er. Pages $60-$7F in banks $80-$BF are still 2.7MHz timing... but usually RAM access speed doesn't add up to much, because so many cycles are spent loading instructions (using K bank) relative to I/O cycles (using B bank)
93143
Posts: 1715
Joined: Fri Jul 04, 2014 9:31 pm

Re: How well can Metal Slug backgrounds be recreated with ti

Post by 93143 »

Yeah, but most of $2000-$5FFF is fast, and large parts of it are unused. Any SRAM in that area could also be mapped into bank $00 for use with direct page and rewritable interrupt routines. All you need is the ability to wire up your own cartridge, or an emulator with manifest support.


How does using bank $A0 rather than $80 help avoid register juggling?

Is it really 20-30 lines for the whole frame, or is it 20-30 lines for one metasprite?
Post Reply