|
| Author |
Message |
|
Dreamland Fantasy
|
Posted: Sat Nov 24, 2007 2:15 pm |
Joined: Fri Dec 29, 2006 1:15 am Posts: 495 Location: Glasgow, UK
|
Hi guys,
I'm planning on getting the BBC Sprite Designer underway. What I need from people are features you would need incorporated into the software.
I have a very basic sprite designer up and partially running at the moment that has the following features:
- Loading of image files (BMP, JPG, PNG, etc.)
- Set size and mode of sprite
- Very basic drawing facilities which allows you to paint pixels
- Add/delete frames (for animated sprites)
So far I have had the following requests:
- Output to VDU/DATA statements
- Accept input of animated GIFs
- Allow selection of a palette
- Allow resize (if required)
- Output the frames to a memory location of your choice (under BeebEm), then produce basic or fast asm code to call and activate the animation!!!!
Kind regards,
Francis.
_________________ Dreamland Fantasy Studios http://www.dfstudios.co.uk
|
|
|
|
 |
|
sorvad
|
Posted: Sat Nov 24, 2007 2:52 pm |
Joined: Wed Aug 24, 2005 1:13 pm Posts: 2128 Location: Back of beyond
|
|
Sounds great Francis, think you've got most bases covered. I'd like the facility to add a sprite mask. We'd have to agree on the output format for this though, as either a colour ref in the png (or whatever) that is not in the palette or as abit map mask.
Not all games require this, some use one of the existing colours to designate the mask in which case the mask type I've mentioned above doesn't matter, but some like it separate for occasions when you want to use all colours properly in a sprite.
I'm probably being vague there, if you want more details I can supply them. And no rush for this if you want to get a version out without it first.
|
|
|
|
 |
|
Rich Talbot-Watkins
|
Posted: Sat Nov 24, 2007 3:56 pm |
Joined: Thu Jan 13, 2005 6:20 pm Posts: 595 Location: Málaga, Spain
|
Thought I'd just share my experience of sprite designing and exporting, in case it proves helpful in some way.
In the past, I used to use the Acorn Sprite Rom on the Master welcome disc ("Spriter"), and use the admittedly shocking editor to create a set of sprites (e.g. player character animation frames, or background map tiles). Then, for each set of sprites, I would write a Basic program which would display them one-by-one at the top-left of the screen (via PLOT &EF, x, y), and copy them into a block of memory in my own arrangement, before finally saving this block out as my 'raw' data.
I found I nearly always needed the data in just two particular arrangements, depending on how the sprites were being used.
For sprites which are being plotted only at character-block aligned positions (e.g. background map tiles), the data's most useful in the 'conventional' format, i.e. as per the BBC screen layout.
Here's a Basic fragment which would take an 12x24 MODE 2 sprite plotted at the very top of the screen and convert it into this format:
Code: FOR row%=0 TO 2 FOR x%=0 TO 47 STEP 4 x%!(sprbase%+row%*48)=x%!(&3000+row%*640) NEXT NEXT
Then, you would plot a sprite like this via the most simple type of sprite routine, which might look a little like this: Code: \\ on entry: \\ (sprdata, sprdata+1) -> base of sprite to plot \\ (screen, screen+1) -> screen address to plot at .simplesprite LDX #2 .spriterow LDY #47 .spriteloop \ unroll a little for extra speed LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY LDA (sprdata),Y:STA (screen),Y:DEY BPL spriteloop DEX:BMI finished \ move screen address pointer to next screen row CLC:LDA screen:ADC #&80:STA screen:LDA screen+1:ADC #2:STA screen+1 \ move sprite address pointer to next sprite row \ C is clear here LDA sprdata:ADC #48:STA sprdata:BCC spriterow:INC sprdata+1 \ Z flag guaranteed to be clear here BNE spriterow .finished RTS
For sprites which need to be able to be plotted at any screen line, the routine is much more complicated due to the awkward non-linear Beeb screen layout. I always found that the most useful format in this particular instance was 'column first', i.e. putting a whole column's worth of data in a contiguous block, like this Basic fragment here: Code: FOR column%=0 TO 5 FOR row%=0 TO 2 FOR n%=0 TO 7 STEP 4 n%!(sprbase%+row%*8+column%*24)=n%!(&3000+row%*640+column%*8) NEXT NEXT NEXT
The sort of routine you could use to plot this might then look a little like this: Code: \\ on entry: \\ (plotcolumn+1, plotcolumn+2) -> base of sprite to plot \\ (screen, screen+1) -> address of top of character block to plot at \\ Y = which line within character block .complexsprite LDA #6:STA columns LDA screen:STA screentemp LDA screen+1:STA screentemp+1 STY ytemp .foreachcolumn LDX #0 .plotcolumn LDA &FFFF,X \ self-modified STA (screen),Y INX:CPX #24:BEQ donerow INY:CPY #8:BCC plotcolumn \ C already set when we get here LDA screen:ADC #&7F:STA screen:LDA screen+1:ADC #2:STA screen+1 LDY #0:BEQ plotcolumn .donerow \ C already set when we get here DEC columns:BEQ finished LDA plotcolumn+1:ADC #23:STA plotcolumn+1 BCC skiphibyteinc:INC plotcolumn+2:CLC:.skiphibyteinc LDY ytemp LDA screentemp:ADC #7:STA screentemp:STA screen LDA screentemp+1:ADC #0:STA screentemp+1:STA screen+1 \ Z guaranteed to be clear here BNE foreachcolumn .finished RTS
(Disclaimer: all totally untested code! If it doesn't assemble, crashes your Beeb, or burns your lasagne, it's not my fault, honest!)These are by no means totally optimal (though I can't stop myself from optimising the code as I write it to some extent...) - for example, the 'complex' sprite routine would be better if it plotted the sprites from the bottom upwards, saving the two CPX/CPYs in the innermost part of the loop, but this is left as an exercise...blah blah.... So to cut a long rambling post vaguely short-ish, support for these two export formats would be great! Oh, masks! (am I ever gonna shut up?)sorvad mentioned masks... well, certainly in a 4 colour mode, they're necessary if you want to avoid horrible-looking EOR mode plotting. I would treat mask data as totally separate from sprite data (don't try to interleave them or anything in the export), and effectively the mask just contains white pixels for transparent, and black pixels for opaque. Then, instead of: Code: LDA (sprdata),Y STA (screen),Y
you use: Code: LDA (screen),Y AND (maskdata),Y EOR (sprdata),Y STA (screen),Y
or similar.
In Mode 2, I would say that exporting a separate mask is not necessary, as it doubles your sprite data size, and there are already redundant bits in the sprite data (which represent colours 8-15) which can happily be used to indicate transparent pixels, though your sprite routine then needs to be a little more clever!
OK, I'm out of here, I'm all sprited-out!
|
|
|
|
 |
|
sorvad
|
Posted: Sat Nov 24, 2007 6:43 pm |
Joined: Wed Aug 24, 2005 1:13 pm Posts: 2128 Location: Back of beyond
|
Concur with all you said, also
Rich Talbot-Watkins wrote: These are by no means totally optimal (though I can't stop myself from optimising the code as I write it to some extent...) - for example, the 'complex' sprite routine would be better if it plotted the sprites from the bottom upwards, saving the two CPX/CPYs in the innermost part of the loop, but this is left as an exercise...blah blah....
A good coder always goes down ! Well numerically speaking  Just to clarify bottom upwards is referring to the screen but is actually counting down  Reason being is that if you reach zero you can detect this without having to check if the value is zero first and saves you some processor cycles and in the inner loops of sprite plotting you want to save all you can
Hope you don't mind me expanding on that Rich 
|
|
|
|
 |
|
Dreamland Fantasy
|
Posted: Sat Nov 24, 2007 10:11 pm |
Joined: Fri Dec 29, 2006 1:15 am Posts: 495 Location: Glasgow, UK
|
|
@sorvad & Rich
Thanks for your comments and suggestions.
Kind regards,
Francis.
_________________ Dreamland Fantasy Studios http://www.dfstudios.co.uk
|
|
|
|
 |
|
garfield
|
Posted: Sat Nov 24, 2007 11:11 pm |
Joined: Mon Jan 03, 2005 2:38 am Posts: 369
|
|
Plotting downwards is also marginally better when it comes to 'beating the timeout' on flicker-free plotting, since the raster gun works from top to bottom.
|
|
|
|
 |
|
garfield
|
Posted: Sun Apr 27, 2008 1:29 am |
Joined: Mon Jan 03, 2005 2:38 am Posts: 369
|
Rich Talbot-Watkins wrote: Code: \\ on entry: \\ (plotcolumn+1, plotcolumn+2) -> base of sprite to plot \\ (screen, screen+1) -> address of top of character block to plot at \\ Y = which line within character block .complexsprite LDA #6:STA columns LDA screen:STA screentemp LDA screen+1:STA screentemp+1 STY ytemp .foreachcolumn LDX #0 .plotcolumn LDA &FFFF,X \ self-modified STA (screen),Y INX:CPX #24:BEQ donerow INY:CPY #8:BCC plotcolumn \ C already set when we get here LDA screen:ADC #&7F:STA screen:LDA screen+1:ADC #2:STA screen+1 LDY #0:BEQ plotcolumn .donerow \ C already set when we get here DEC columns:BEQ finished LDA plotcolumn+1:ADC #23:STA plotcolumn+1 BCC skiphibyteinc:INC plotcolumn+2:CLC:.skiphibyteinc LDY ytemp LDA screentemp:ADC #7:STA screentemp:STA screen LDA screentemp+1:ADC #0:STA screentemp+1:STA screen+1 \ Z guaranteed to be clear here BNE foreachcolumn .finished RTS
(Disclaimer: all totally untested code! If it doesn't assemble, crashes your Beeb, or burns your lasagne, it's not my fault, honest!)These are by no means totally optimal (though I can't stop myself from optimising the code as I write it to some extent...) - for example, the 'complex' sprite routine would be better if it plotted the sprites from the bottom upwards, saving the two CPX/CPYs in the innermost part of the loop, but this is left as an exercise...blah blah....
If one was trying to 'beat the raster redraw' (i.e. getting the very maximum flicker-free plot time for sprites in a frame before the beam catches up to one's drawing), surely plotting sprites from top to bottom would allow (slightly) more redraw time than plotting sprites from bottom to top, before the crt gun passes down the screen?
It seems to me that the maximised window of time to plot a sprite is achieved by setting a timer to coincide with the redraw beam having just passed down past the last line of one's sprite, and the timer's callback routine draws the next sprite from top-to-bottom. The largest non-flickering sprite would be the kind that has its last line plotted just before the crt gun overtakes it!
|
|
|
|
 |
|
Neil
|
Posted: Sun Apr 27, 2008 11:43 am |
Joined: Thu Apr 17, 2008 12:56 pm Posts: 33 Location: Northampton
|
Aww its nice to see so many game coders discussing stuff ... I've been coding for 30 years (holy poo!), never on the beeb thou!!
Whats nice is the thought and effort of comments - so a big thumbs up frfom me!!
Well, I'll have to get stuck in, lots to learn!!
-
thanks - Neil
_________________ ---------------------------------------------------
We live for the one, we die for the one!
|
|
|
|
 |
|
Rich Talbot-Watkins
|
Posted: Mon Apr 28, 2008 8:49 am |
Joined: Thu Jan 13, 2005 6:20 pm Posts: 595 Location: Málaga, Spain
|
garfield wrote: If one was trying to 'beat the raster redraw' (i.e. getting the very maximum flicker-free plot time for sprites in a frame before the beam catches up to one's drawing), surely plotting sprites from top to bottom would allow (slightly) more redraw time than plotting sprites from bottom to top, before the crt gun passes down the screen? Yeah, that's true. But the 'plotting from bottom-up' change is a speed optimisation, which saves 4 clock cycles per byte - something which could add up to a significant saving if you plot enough sprites per frame. As it goes, the plotting direction doesn't really matter so much in this routine, because the sprite is plotted in separate columns from left to right which means that if you intersect the raster redraw, you'll probably still see an artefact in one of the columns. Quote: It seems to me that the maximised window of time to plot a sprite is achieved by setting a timer to coincide with the redraw beam having just passed down past the last line of one's sprite, and the timer's callback routine draws the next sprite from top-to-bottom. The largest non-flickering sprite would be the kind that has its last line plotted just before the crt gun overtakes it!
Yep, that's true! But in practice, in a game, this is hard, because you probably can't guarantee the y positions of the sprites every frame. But you can still help the flicker problem by sorting the sprites by y position first, and then plotting them in that order, after the raster has reached the lowest point of the game window.
My spinning dots demo in BeebAsm makes optimal use of these raster timings. First all the dots are plotted from highest to lowest. Then they are all erased in the same order. The demo is timed so that the erasing starts such that when the last dot is erased, the raster beam is at the lowest y coordinate of the globe, ready for the plotting part again. This is only possible though because the y positions are fixed and very carefully chosen to be spread out evenly.
|
|
|
|
 |
|
sorvad
|
Posted: Mon Apr 28, 2008 9:16 am |
Joined: Wed Aug 24, 2005 1:13 pm Posts: 2128 Location: Back of beyond
|
|
Also Rich mentions plotting in columns, i.e. column 0 column 1 etc. from bottom to top.
Why not plot horizontal you may ask ? i.e. a row at a time. Well, because of the way the Beebs memory map is organised by the 6845 (which is optimised to plot ascii characters) it would take even more clock cycles to do this than working in byte columns.
|
|
|
|
 |
|
garfield
|
Posted: Mon Apr 28, 2008 10:58 am |
Joined: Mon Jan 03, 2005 2:38 am Posts: 369
|
By the way guys, where 'physically speaking', does the vsync interrupt correspond to on-screen? Is it conceptually at the very bottom of the frame, or at the very top of the next frame (if the distinction matters at all!)?
And is it correct to assume that the redrawing crt gun is just slightly ahead of the point where the vsync interrupt was issued when you actually get to service it?

|
|
|
|
 |
|
sorvad
|
Posted: Mon Apr 28, 2008 11:33 am |
Joined: Wed Aug 24, 2005 1:13 pm Posts: 2128 Location: Back of beyond
|
|
Looking at the advanced user guide it seems to be after the last row from memory is displayed. But I'm not 100% if this is the case, Rich may know better.
And yes, the electron beam will be slightly ahead of where Vsync occurred by the time you get to service it due to interupt latency and time to process interupt handler OS code.
|
|
|
|
 |
|
Rich Talbot-Watkins
|
Posted: Mon Apr 28, 2008 12:11 pm |
Joined: Thu Jan 13, 2005 6:20 pm Posts: 595 Location: Málaga, Spain
|
garfield wrote: By the way guys, where 'physically speaking', does the vsync interrupt correspond to on-screen? Is it conceptually at the very bottom of the frame, or at the very top of the next frame (if the distinction matters at all!)?
Actually, neither! The best way to explain it is with reference to the CRTC registers.
Let's take MODE 2 as an example.
First of all, remember we have 312 lines in a PAL screen - or 39 character rows of 8 scanlines (39*8=312). These are defined here:
CRTC R4 = 38 (vertical total minus 1)
CRTC R9 = 7 (scanlines per character minus 1)
Now MODE 2 has 32 visible rows, and this is defined here:
CRTC R6 = 32 (vertical displayed)
This means we have 7 rows which are unaccounted for - these in fact comprise the top and bottom borders and the vertical flyback period. So whenabouts in these is the VSync?
The answer is to look at CRTC R7 which defines the screen row at which VSync occurs. Looking at the AUG, we see that, by default for MODE 2, VSync is programmed to occur at line 34, i.e. after two rows of border after the screen has 'finished'.
Now, VSync is a signal to the VDU to commence vertical flyback, i.e. bringing the beam position back to the top of the screen. This doesn't happen in an instant, but of course requires some time. How long?
Well, we know that we have two blank rows before VSync. We also know that the screen is more-or-less centred on the monitor, so it makes sense that we also have two blank rows of border before the 'actual' screen is displayed. So if we have in total 4 blank rows displayed as border, it follows that we are using roughly 3 rows for the flyback period.
Thus we can breakdown the screen like this:
top border CRTC row 37
top border CRTC row 38 ________
screen row 0
screen row 1
......
screen row 30
screen row 31 ________
bottom border CRTC row 32
bottom border CRTC row 33
VSync row 34 *
* at this point, flyback begins, and three rows later, the CRT beam is back to the very top of the TV's physical display (at CRTC row 37), ready to emit 2 further lines of border before commencing the memory-mapped display.
Now you can see how changing the value of CRTC R7 vertically displaces the screen by character row amounts, just like *TV. If, for example, the VSync position were changed to row 32, the screen would be moved down, due to the CRT beam reaching the top of the screen at CRTC row 35, resulting in 4 rows of top border instead of 2.
So, the other thing is that using the VSync to time new frame rendering is not really ideal. Better is to set off a timer relative to VSync which interrupts as soon as the raster is just beyond the bottom of the game area. This gives you as much time as possible to render the next frame!
|
|
|
|
 |
|
sorvad
|
Posted: Mon Apr 28, 2008 12:43 pm |
Joined: Wed Aug 24, 2005 1:13 pm Posts: 2128 Location: Back of beyond
|
Absolutely great reply Rich  Your the man with those CRT registers for sure !
|
|
|
|
 |
|
garfield
|
Posted: Mon Apr 28, 2008 1:36 pm |
Joined: Mon Jan 03, 2005 2:38 am Posts: 369
|
|
Thanks Rich and Sorvad. Very well explained!
|
|
|
|
 |
|
|