Sprite help
Pages: 1 2
Andrew Fawthrop (326) 25 posts |
I have an Iyonix running version 5.20 (10 Jun 13) version of Risc Os. As my first programming project I’m trying to write a text editor. All it does at this stage is fill the screen with lines of text and wraps them. I go to a particular point in the text and press the delete key until the top of the page is reached. I’m timing how long this takes in order to get the most speed out of my program as possible at this early stage so that what I then build on top will be fairly nippy. I’ve got the speed down from 60 seconds to 6 seconds. But am trying to get the “engine” running to one second. In order to try to do that and so that this program can be put into the desktop fairly easily I thought I’d write directly to a sprite instead of the screen and write part of the sprite for lines and characters that have changed. To understand the PRM I’ve written a very simple sprite library so that I could play around easily with the different SYS commands. I’m stuck on working out how much memory a sprite needs to have allocated for any mode. The ideal would have been to use something like 256+62 (Read save area size). I did not understand the PRM or wasn’t able to understand it’s output as anything I could use. So rather than use a built in call, or generate a simple formula to calculate the save area size for a sprite the size of the screen I was going to create I thought I’d create a sprite of one pixel by one pixel and times the result out by the dimensions of the screen to get the total sprite area size. This should work as I can use 256+8 (Read area control block) to find the byte offset to the first free word which is the total size of memory used to accomodate the sprite. However, during testing I found that my program would say that it couldn’t find the name sprite unless I set the sprite to be eight pixels by eight pixels. The reason for that appears to be because the sprite name isn’t been created when I try to read it with 256+13 (Return name) if the sprite is one pixel by one pixel. So I went back to the earlier idea of creating a formula to calculate the save area required. I worked out that the relationship the sprite (with no palette) is: SYS"OS_SpriteOp",256+8,spritemem% TO r0%,r1%,r2%,r3%,r4%,r5% And the formula needs extending to account for the amount of colours on the screen. For my screen mode I have 16 million colours. The following works for any mode except 16 million. If it’s 16 million the logical colours returns -1: SYS “OS_ReadModeVariable”,MODE,3 TO ,,colour% Maybe I need to use a memory block !colour%? Thinking about it though if the OS knows if a save area isn’t big enough for sprite it tells you. I’d guess that the OS wouldn’t try to fill an area with a sprite too large and then after failing to complete the fill return an error message. The OS should have a formula that checks the save area size and report an error if the area isn’t large enough. If that formula is in the OS sources then I can use it and that would really be ideal because it should hopefully work on any version of the OS. Going forwards I may need to learn either Assembly or C++ but only if I really have to because I understand that if something is slow in BASIC then there’s usually a problem with my code. I’ve purchased C++ version 3.21 for Iyonix because I couldn’t compile any of the sample C++ programs on the NutPI without it erroring. On the Iyonix compiling a C++ program just outputs a data file so I haven’t been able to play with that yet. I’d appreciate any advice on this too. My last question is to do with modes. Why can’t the Iyonix display mode 12 or mode 15, should I be getting a garbled screen when I try to switch to these modes. If I write a program to switch modes and drop it into Aemulor I get the same garbled screen (blocks of multi-coloured pixels). I read somewhere that Aemulor could display these low bpp modes on the Iyonix. Thanks, |
Rick Murray (539) 13840 posts |
Hi, Sorry, I can’t give specifics, I’m having chips in a truck stop (hi John, Pommeniac). The trick with text editors is in knowing what needs to be redrawn. Then, the screen can be updated as necessary without redrawing the entire display. With reference to your pressing the delete key, the least you need to do is handle the delete in the text buffer, and then rub out the character that was on the screen, and adjust the cursor as appropriate. It seems to me that if you can redraw a sprite, you could redraw directly to the screen? How many colours do you need? RISC OS is fully capable of displaying a sprite in a different colour depth than the current MODE. Does it make sense to claim a megabyte or two for a big 16m colour sprite when you only need four colours? ;-) Look at the additional gumph in SpriteOp’s plotting to do with translation tables. The Wimp coordinate system is a bit weird (it goes negative up), but once you tie in the viewport offset with the scroll offset, you can determine what the user is actually seeing. I must admit that I was lazy with a redraw routine I wrote, so simply redrew from the top visible line to the bottom visible line. Nothing else can be seen so can be ignored. When the Wimp asks you to redraw a window (or partial), it sets a clipping rectangle so you can just spit out drawing commands as necessary (rectangle plot, VDU5 text, fonts…) and they’ll appear “in the window”. You must pay attention to make your redraw fast as some actions, such as dragging a menu over the window, will cause a slew of little rectangular parts that will need to be redrawn. It isn’t hard, just damn fiddly for people that suck at maths. |
GavinWraith (26) 1563 posts |
Wow! That is ambitious. Have you looked at (the documentation for) the Zap Redraw module? It does quite a lot of the heavy lifting for displaying text. Best of luck. |
Fred Graute (114) 645 posts |
Yes, that’s definitely the easiest way to start. The main thing with text redraw, IMO, is to first get something that works then start making optimisations. The next bit would be find out at what line the redraw starts and ends using the clipping rectangle given and redraw only that area. How difficult that is will depend on the type of font you want to use: system font, an outline font or custom bitmap font. The first two are relatively easy as the OS will apply the clipping rectangle for you but for custom bitmap fonts you’ll need to do everything yourself. Plotting to a sprite first and then rendering that to the screen probably isn’t going to bring you much, in fact it seems to make things more complicated. My advice would be to first decide what font to use (system font would be easiest to start with) then plot some text somewhere on the screen. Once that works correctly (font, colours) add a window and plot the text in its top-left corner. If that works, add support for redraw requests so that the text is redrawn when a window is dragged over it. That may seem simplistic but if you’ve never done this before it will probably cause some headaches, as Rick says the coordinate system is weird and takes some time to get one’s head around. Besides I can vouch for the viability of this approach – it’s how I started adding outline font support to StrongED. :-) |
Steve Pampling (1551) 8170 posts |
Purely personal opinion but I’d say for almost everything the actual tack is best expressed as: “The main thing is to first get something that works, then start making optimisations” |
John Williams (567) 768 posts |
Find a clearer system font here |
Andrew Fawthrop (326) 25 posts |
Hi, Thanks for such positive feedback. I was thinking previously about outputting to a sprite created in a different mode and then displaying it for more speed gains but also because this facility seems to be so useful generally. I was wondering about StrongEd and it appeared as though that was doing the system font in a set mode indepent of what the desktop is in. I’d need to scale the system font though. So I thought I’d get the allocation of the correct amount of sprite memory for the area prior to creating the sprite working first. I feel as though the OS must have a formula that checks the sprite area is big enough before allowing me to create the sprite because it tells you the sprite area isn’t large enough before it allows you to create the sprite. Where do I get hold of the sources please and where should I start to look? I don’t mind buying them. I’ve purchased draganddrop magazines as they have useful articles on sprites that I can hopefully use. It’s going to be a text editor so it’ll use the system font for now. It’s primarily a means to learn as much as I can myself and make the editor as quick as I can so what I want it to do to start with is a simple as possible so no fonts, formatting etc. with the current design. Putting it into the desktop is a long way off. I haven’t got around to looking at the different tools available yet. I may end up writing my own code to do the WIMP stuff if I find that sufficiently interesting. I couldn’t find riscoslib’s txt module in the DDE documentation or stronged’s documentation when I had a quick search for it the other day will try again. I like Gavin’s idea of having two stacks it’s like I guess having an index on each character so no text needs to be shuffled in memory just an update to the index (next or previous) on each stack’s item. The main slowness is the printing the display after a delete. I know I probably won’t gain much by writing out part of a sprite that contains the lines and characters that have changed like I can direct to the screen now but I’m not making any assumptions so am literally timing every line of code. It was quite surprising how much can be gained by approaching the project in this way and it was starting to give me a good guess at what the interpreter was doing behind the seens. It was quite interesting that if you go down one road with the design like checking the lines that have changed on a word wrap and the characters that are different and only displaying those changes that whilst write_n and pretty print for the whole screen may be quicker in seperate testing but the overall speed is quicker in the way I’ve done it. So having two stacks would need to be thought about a lot more. If I can’t get the deletion down to one second I’ll reappraise how the whole program is designed and look into the stack idea. It’s all great fun. In my post I describe one issue where if two sprites are created 1 pixel by 1 pixel the sprite names are getting lost. I’ve investigated this further and have found a pattern, here is what I found out: Creating two sprites in a given sprite area one pixel by one pixel. You have to create two sprites to make it fail. So two sprites one pixel by one pixel. I’ve examined the output from a byte dump of the sprite area and what it’s doing when it fails is wipe out (setting to zero) all the bytes from byte 64 downwards. Byte 68,69,70 is the second sprites name. Thanks again, |
Colin (478) 2433 posts |
I can’t see the need to use a sprite – I didn’t when I wrote a text editor – but if that’s the way you want to go…
Not for me it doesn’t. The program below wouldn’t be able to plot the first sprite or select the second sprite if the names were corrupted.
|
Andrew Fawthrop (326) 25 posts |
DIM data% areasize% SYS “OS_SpriteOp”, 9 + 256, data%: REM Initialise sprite area REM create sprites from scratch. REM SYS “OS_SpriteOp”, 16 + 256, data%, “test”,0,0,0,xwid%,yht%: REM get sprite PRINT"Comment this print command out and second sprite can be found" SYS “OS_SpriteOp”, 60 + 256, data%, “test”, 0 TO r0%,r1%,r2%,r3%: REM switch output to sprite REM …Or uncomment next line vdu 5 and second sprite can be found SYS “OS_SpriteOp”, r0%,r1%,r2%,r3%: REM restore output SYS “OS_SpriteOp”, 34 + 256, data%, “test”, 512,512,0: REM plot sprite REM also fails – SYS “OS_SpriteOp”, 24 + 256, data%, “test2”: REM select sprite END |
Andrew Fawthrop (326) 25 posts |
Hi Colin, I compared your code with my code that was failing. Stripped out all of the procedures etc. from my code. Restarted my machine and was able to reproduce the error whether I create the sprites from scratch or grab a bit of screen as you have done in your code. When I’d done checking my SYS calls and comparing them against yours and striping out my functions/procedures I noticed that if I add a Print command as in the code above it causes the second and third sprites to disappear. If I comment it out then they are selectable. Or if I put in a VDU5 command before drawing in the sprite the sprites don’t disappear. Very strange. I wonder what I’m missing here. |
Andrew Fawthrop (326) 25 posts |
Incidently setting areasize hasn’t pasted across correctly it’s between the onerror and dim data exactly as in your code. Thanks, |
Colin (478) 2433 posts |
Your problem happens because the VDU4 text is clipped to a text window which is character based. The minimum textwindow size is 1 character square so a sprite smaller than that gets overwritten. The reason it worked when you didn’t print anything outside the sprite was because the program was run in the desktop. The first PRINT statement in a program – if you dont use MODE first – changes the text window to the one used by the desktop to output VDU4 text so when the PRINT statement wasn’t used the text window was changed by the PRINT statement in the redirected sprite. The print statement may well have corrupted some other part of the sprite area which wasn’t used so you don’t know about it. If you change the program so it starts with
then the later sprites in the sprite area always get corrupted as this stops the text window change on the first PRINT statement. Sprites > 8 pixels square are not a problem as the text window can be limited to inside the sprite. The conclusion is if you want the sprite to include space around characters – linespacing, margins – then you can’t use VDU4 as it doesn’t allow you to place text on pixel boundaries. Ensuring that it is > 8 pixels square isn’t really a problem but if you don’t make the sprite height and width a multiple of 8 you will be left with a part of the sprite you can’t write to with VDU4 chars. Also note VDU4 characters don’t clip to the text window they wrap and scroll so a 8 pixel sprite will show Y after the statement:
whereas if it was VDU5 text it would show X. Tip: If you want to post unmangled code start the code with ’bc. ’ at the beginning of the line – like you use ’bq. ’ for quotes. If the code contains blank lines use ’bc.. ’ and start the first paragraph after the code with ’p. ’ |
Rick Murray (539) 13840 posts |
It is better to use VDU5 text from the outset. Why? Because the behaviour of both is different and the Wimp deals with VDU5 text only (as the window placement is arbitrary so VDU4 won’t work). |
Andrew Fawthrop (326) 25 posts |
Thanks for explanation. I’ll use vdu5. To check my understanding: Print statements set up a text window, unless the mode has been changed. If a mode change occurs the text window size is set to the size of the screen. When a text window has been set up it’s used later with the redirection of vdu output in the sprite, and that would also include the text window created by a mode change. If the text window isn’t the correct size for the sprite i.e. the sprite is too small and the text window is too large, the sprite area gets corrupted. If a text window has not been set up when I redirect vdu output to a sprite the system then creates a text window in the sprite, this has to be at least 1 character height by 1 character width. If the sprite size is smaller than the size of a character then sprite corruption occurs. The text window acts as a boundary in the sprite area, it is what stops bytes in the sprite area from getting changed when they shouldn’t be. |
Colin (478) 2433 posts |
Only the first print statement and only if the program is single tasking and run from the desktop. So if you have the program:
and double click on it on the desktop a text window will appear with
in it. That text window is created when the ‘H’ in hello is sent to the VDU drivers.
Yes
No. When the sprite is redirected it sets up its own text window based on the size of the sprite. The text window coords are left column, bottom row, right column, top row. A 1 pixel square sprite gets a text window of 0,-1,-1,0, a 8-15 pixel square sprite gets a 0,0,0,0 text window. The 0,-1,-1,0 window is the largest window you can have (-1 is read as an unsigned integer) so a sprite with that window will corrupt memory as parts of the window are outside the sprite memory.
Yes but it may not be the sprite area that gets corrupted. If the text window is large enough you may be printing to some part of memory outside the sprite area. The running from the desktop is just another complication. If instead of the above program you had.
and run this by double clicking on the desktop, the text window after redirecting the sprite will be 0,0,0,0 but after printing the ‘H’ in hello this is changed to the desktop text window.
Effectively yes but it’s only a boundary to VDU4 characters, VDU5 characters are bounded by the graphics window which has pixel resolution. |
Rick Murray (539) 13840 posts |
Remind me again please – why are we wanting to print text to a sprite smaller than the size of a character? |
David Feugey (2125) 2709 posts |
Yep, no need :) Make Sprite, redirect and use normal commands. The real two problems are: when the size of the window changes, you need to change the size of the Sprite; it can be slow to print all the Sprite on screen, so you need tools to update only part of the Sprite. This second point will be probably addressed by the OS one day… It would be cool too to have SChoose, etc. commands that use modern way, and would be compatible with windowed mode… directly (and an option to launch BBC Basic in a multitasking graphic window, where the mode command would simply change the size of the window). Off topic. |
Bryan Hogan (339) 592 posts |
GraphTask? http://www.armclub.org.uk/free/ |
David Feugey (2125) 2709 posts |
Excellent software. Was not working on ARMv7 computers last time I did test it. |
Andrew Fawthrop (326) 25 posts |
Hi, Thanks Colin that’s a great explanation (This knowledge may be useful to someone else that hasn’t created a sprite before, you know in terms of general understanding of what the system is doing). I was also wondering why my machine kept having to be rebooted after erroring for what seemed like fairly insignificant changes to my code. I was writing to memory outside the sprite area :) The reason for the 1 pixel by 1 pixel sprite was because I could find no system call that would tell me how much memory I needed to reserve for a sprite that I was going to create full screen. I was going to see how much memory the one pixel by one pixel sprite filled and times that by the size of the screen to get the total memory requirement for a sprite I would then create full screen. I had in my test code a print statement that I’d thrown in at some point during testing. Now that I’m not corrupting the sprite area it’s looking like I’m getting some results that are following a pattern so this approach looks possible. The second approach I was taking was to write a formula to calculate the sprite area size based on mode information. For example if the sprite is created in a 256 colour mode then the memory requirement may be one byte per pixel times the size of the sprite that I’m going to create. That formula wouldn’t work for a mode with more colours as the colours affects the size of the sprite so the formula would need to be changed. But in a 16 million colour mode the colours returned is -1. I haven’t been able to work out why yet. If a sprite area is too small then the OS tells you and I was also wondering about using that validation/check code in my own function to calculate the correct sprite area size for a given sprite size and then allocate it but I didn’t know where I could get the source code from or where it’d be in the source tree. Thanks, |
Rick Murray (539) 13840 posts |
X x Y x bpp (in terms of a byte) + sprite header + sprite area header ? |
Chris Evans (457) 1614 posts |
If masked: |
Rick Murray (539) 13840 posts |
Depends on the sort of mask, doesn’t it? I think add (X x Y) bytes for an alpha transparency, and ((X x Y) / 8) bytes for an old style on/off mask? |
Colin (478) 2433 posts |
The black art of sprite sizing makes the thought of writing a text editor seem simple. There’s: 1) Sprite header The rows of sprite data and mask data are 4 byte aligned. There should be a SpriteOp for this. |
Chris Evans (457) 1614 posts |
Quite right Rick. It’s never as easy as you first think… Apart from the Pi Zero USB fix for non OTG cables, hubs etc. which turned out to be one byte. No I correct myself it was one bit! |
Pages: 1 2