Discussion:
Saving animated sprites from a simple BASIC graphic program
Add Reply
Richard Ashbery
2020-03-17 16:57:26 UTC
Reply
Permalink
I have a simple BASIC program that continuously rotates a square but
offset from the screen centre (1920 x 1080). The screen is cleared for
each rotation step.

I would like to generate a GIF animation that I could use on my
website. I've used the VDU 23,27,1,n| command and then processed the
sprite group through InterGif to create the animated GIF. Dragging GIF
to NetSurf displays the animated square but only rotates around the
screen centre ignoring the offset. How should I do this please? Some
simple code examples would be appreciated.

Richard
John Williams (News)
2020-03-17 17:28:24 UTC
Reply
Permalink
Post by Richard Ashbery
How should I do this please?
I would suggest that this is because InterGif treats the background as
transparent.

Does ticking Transparency None in InterGif make any difference?

If you were to take whole screenshots and process them, then the background
and displacement might be taken into account?

John
--
John WILLIAMS, now back in the UK - no attachments to these addresses!
Non-RISC OS posters change user to johnrwilliams or put 'risc' in subject!
Who is John WILLIAMS? http://petit.four.free.fr/picindex/author/
Richard Ashbery
2020-03-17 20:30:14 UTC
Reply
Permalink
Post by John Williams (News)
Post by Richard Ashbery
How should I do this please?
I would suggest that this is because InterGif treats the background
as transparent.
Does ticking Transparency None in InterGif make any difference?
I thought you were onto something John but setting transparency to
None makes no difference. The sprites themselves show no ORIGIN offset
either. If I delete the CLG command then the offset appears on the
sprites but this is not what I want.

With CLG I get: http://www.riscosbasic.uk/problems/With.zip

Without CLG I get: http://www.riscosbasic.uk/problems/Without.zip
Post by John Williams (News)
If you were to take whole screenshots and process them, then the
background and displacement might be taken into account?
I have a concern that the screenshots would be so memory intensive I
could only gather a few resulting in full rotation being incomplete.
The method I'm using (specified by 2 MOVE commands) constrains the
graphic to a relatively small area. Nevertheless I will try it and see
what happens.

Best regards

Richard
John Williams (News)
2020-03-17 21:12:10 UTC
Reply
Permalink
Post by Richard Ashbery
Post by John Williams (News)
Post by Richard Ashbery
How should I do this please?
I would suggest that this is because InterGif treats the background
as transparent.
Does ticking Transparency None in InterGif make any difference?
I thought you were onto something John but setting transparency to
None makes no difference. The sprites themselves show no ORIGIN offset
either. If I delete the CLG command then the offset appears on the
sprites but this is not what I want.
With CLG I get: http://www.riscosbasic.uk/problems/With.zip
Without CLG I get: http://www.riscosbasic.uk/problems/Without.zip
Post by John Williams (News)
If you were to take whole screenshots and process them, then the
background and displacement might be taken into account?
I have a concern that the screenshots would be so memory intensive I
could only gather a few resulting in full rotation being incomplete.
The method I'm using (specified by 2 MOVE commands) constrains the
graphic to a relatively small area. Nevertheless I will try it and see
what happens.
One tries to help - but one ain't no expert!

John
--
John WILLIAMS, now back in the UK - no attachments to these addresses!
Non-RISC OS posters change user to johnrwilliams or put 'risc' in subject!
Who is John WILLIAMS? http://petit.four.free.fr/picindex/author/
Richard Ashbery
2020-03-17 21:23:32 UTC
Reply
Permalink
[snip]
Post by John Williams (News)
Post by Richard Ashbery
The method I'm using (specified by 2 MOVE
commands) constrains the graphic to a relatively small area.
Nevertheless I will try it and see what happens.
One tries to help - but one ain't no expert!
Any help is appreciated John.

Regards

Richard
News
2020-03-17 23:39:47 UTC
Reply
Permalink
Have you tried plotting using exclusive OR (EOR) to do the plotting.
You plot the shape twice using EOR, the second plot effectively
deletes the shape just plotted. Then you recalculate the coordinates
and plot twice again. In this way you do not need any CLG, which
resets things each time.

You set the EOR action using GCOL 3, n. and then use the appropriate
plot command, eg LINE 9,0,100,100.
--
Chris Johnson
Steve Fryatt
2020-03-17 22:44:12 UTC
Reply
Permalink
On 17 Mar, Richard Ashbery wrote in message
How should I do this please? Some simple code examples would be
appreciated.
Is there any chance of seeing your current code?
--
Steve Fryatt - Leeds, England

http://www.stevefryatt.org.uk/
Richard Ashbery
2020-03-18 17:44:29 UTC
Reply
Permalink
Post by Steve Fryatt
On 17 Mar, Richard Ashbery wrote in message
How should I do this please? Some simple code examples would be
appreciated.
Is there any chance of seeing your current code?
MODE 1920,1080,32 : OFF
T2=0
n=0
REM Set up rotation variable for square
FOR m=0 TO 6*PI-PI/12 STEP PI/6
REM Set offset for ORIGIN (full circle)
X1=SIN RAD(T2)*100
Y1=COS RAD(T2)*100
ORIGIN 1920+X1,1080+Y1
T2+=10
GCOL 3,63 : PROCdraw_square
z=INKEY(10)

REM Generate sprite group for animation
MOVE-330,-330
MOVE 330,330
VDU 23,27,1,n|
n+=1

REM Erase previous square after a delay
GCOL 3,63 : PROCdraw_square

NEXT m
END

DEF PROCdraw_square
FOR T = 0 TO 2*PI STEP PI/2
X=SIN(T+m)*200
Y=COS(T+m)*200
IF T=0 THEN MOVE X,Y ELSE DRAW X,Y
NEXT T
ENDPROC

As suggested by Chris I've eliminated CLG and substituted the EOR
GCOL 3,63. Running program displays an offset square as expected but
when the sprites are saved the offset is missing and clearly absent when
viewing sprites in !Paint. Could this be a problem with the way the
program collects the sprite data?

The rather strange looking FOR m=0 TO 6*PI-PI/12 STEP PI/6 statement
ensures the rotation of the shape returns to its start position and
avoids judder when the animation starts again.


Richard
druck
2020-03-18 20:55:33 UTC
Reply
Permalink
Post by Richard Ashbery
REM Generate sprite group for animation
MOVE-330,-330
MOVE 330,330
VDU 23,27,1,n|
n+=1
I would guess this is where your problem is, as you are not making a
sprite from the whole screen, but from the rectangle defined by these
points.

I would not recommend using the ancient VDU codes for dealing sprites -
this is BBC Micro era stuff and deprecated many many decades ago. Use
OS_SpriteOp instead.

---druck
Steve Fryatt
2020-03-19 00:08:45 UTC
Reply
Permalink
On 18 Mar, Richard Ashbery wrote in message
As suggested by Chris I've eliminated CLG and substituted the EOR GCOL
3,63. Running program displays an offset square as expected but when the
sprites are saved the offset is missing and clearly absent when viewing
sprites in !Paint. Could this be a problem with the way the program
collects the sprite data?
As Druck says, VDU23,27,1,n| is ugly, and quite dated. I wouldn't be
completely surprised if it doesn't take the ORIGIN setting into account, but
I can't see any reference to that foible in the manual.

However, using ORIGIN seems unnecessary anyway. Why not just plot at the
required coordinates, and bypass all of the problems?

MODE 1920,1080,32 : OFF
T2=0
n=0
REM Set up rotation variable for square
FOR m=0 TO 6*PI-PI/12 STEP PI/6
REM Set offset for ORIGIN (full circle)
X1=SIN RAD(T2)*100
Y1=COS RAD(T2)*100
T2+=10
GCOL 3,63 : PROCdraw_square(1920+X1, 1080+Y1, m)
z=INKEY(10)

REM Generate sprite group for animation
MOVE1920-330,1080-330
MOVE1920+330,1080+330
VDU 23,27,1,n|
n+=1
REM Erase previous square after a delay
GCOL 3,63 : PROCdraw_square(1920+X1, 1080+Y1, m)

NEXT m
END

DEF PROCdraw_square(x%, y%, angle)
FOR T = 0 TO 2*PI STEP PI/2
X=x%+SIN(T+angle)*200
Y=y%+COS(T+angle)*200
IF T=0 THEN MOVE X,Y ELSE DRAW X,Y
NEXT T
ENDPROC
--
Steve Fryatt - Leeds, England

http://www.stevefryatt.org.uk/
Steve Fryatt
2020-03-19 07:38:28 UTC
Reply
Permalink
On 19 Mar, Steve Fryatt wrote in message
Post by Steve Fryatt
On 18 Mar, Richard Ashbery wrote in message
As suggested by Chris I've eliminated CLG and substituted the EOR GCOL
3,63. Running program displays an offset square as expected but when the
sprites are saved the offset is missing and clearly absent when viewing
sprites in !Paint. Could this be a problem with the way the program
collects the sprite data?
As Druck says, VDU23,27,1,n| is ugly, and quite dated. I wouldn't be
completely surprised if it doesn't take the ORIGIN setting into account,
but I can't see any reference to that foible in the manual.
Actually, the reason this is happening is obvious, at least after a night's
sleep.

You're grabbing a screenshot from (-330,-330) to (330,330) relative to the
current origin (0,0), but at the same time, you're moving that origin around
to shift the centre of your square. But, of course, this /also/ moves the
centre of the (-330,-330) to (330,330) screen grab, so the grabbed area will
/always/ be perfectly centred on the square that you've just plotted.

I still don't like VDU23,27,1,n| though...
Post by Steve Fryatt
However, using ORIGIN seems unnecessary anyway. Why not just plot at the
required coordinates, and bypass all of the problems?
By not moving the (0,0) point around, but instead plotting the square at the
desired coordinates relative to a single, fixed origin, the square will, of
course, move within the static (-330,-330) to (330,330) rectangle as
intended.

I would suggest treating ORIGIN as a command to call once, after MODE. After
that, always calculate the exact coordinates that you need for each stage of
the graphic. This is no harder than moving the origin, as you can see from
my code, and completely avoids this kind of confusion.
--
Steve Fryatt - Leeds, England

http://www.stevefryatt.org.uk/
News
2020-03-19 10:17:24 UTC
Reply
Permalink
Post by Steve Fryatt
You're grabbing a screenshot from (-330,-330) to (330,330) relative
to the current origin (0,0), but at the same time, you're moving
that origin around to shift the centre of your square. But, of
course, this /also/ moves the centre of the (-330,-330) to
(330,330) screen grab, so the grabbed area will /always/ be
perfectly centred on the square that you've just plotted.
Those were my thoughts as well, but you beat me to the post 8)
--
Chris Johnson
Richard Ashbery
2020-03-19 20:05:53 UTC
Reply
Permalink
Post by Steve Fryatt
On 19 Mar, Steve Fryatt wrote in message
Post by Steve Fryatt
On 18 Mar, Richard Ashbery wrote in message
be a problem with the way the program collects the sprite data?
As Druck says, VDU23,27,1,n| is ugly, and quite dated. I wouldn't
be completely surprised if it doesn't take the ORIGIN setting
into account, but I can't see any reference to that foible in the
manual.
You're grabbing a screenshot from (-330,-330) to (330,330) relative
to the current origin (0,0), but at the same time, you're moving
that origin around to shift the centre of your square. But, of
course, this /also/ moves the centre of the (-330,-330) to
(330,330) screen grab, so the grabbed area will /always/ be
perfectly centred on the square that you've just plotted.
Ah! yes obvious when I think about it.
Post by Steve Fryatt
I still don't like VDU23,27,1,n| though...
Although this method of creating a sprite group is probably
poor/deprecated it's easy to understand.

I need to get my head round the alternative (OS_SpriteOp). Although
I've been told its easy the last time I looked I didn't find it plain
sailing - I need a good tutorial - I'll do a web search and see what
turns up.
Post by Steve Fryatt
Post by Steve Fryatt
However, using ORIGIN seems unnecessary anyway. Why not just plot
at the required coordinates, and bypass all of the problems?
By not moving the (0,0) point around, but instead plotting the
square at the desired coordinates relative to a single, fixed
origin, the square will, of course, move within the static
(-330,-330) to (330,330) rectangle as intended.
Excellent explanation - thanks :-)

Of course your program changes work superbly. Again thanks.
Post by Steve Fryatt
I would suggest treating ORIGIN as a command to call once, after
MODE. After that, always calculate the exact coordinates that you
need for each stage of the graphic. This is no harder than moving
the origin, as you can see from my code, and completely avoids this
kind of confusion.
Yes, I see that now and is vastly better.

Richard
Steve Fryatt
2020-03-19 21:10:28 UTC
Reply
Permalink
On 19 Mar, Richard Ashbery wrote in message
Post by Richard Ashbery
Post by Steve Fryatt
I still don't like VDU23,27,1,n| though...
Although this method of creating a sprite group is probably
poor/deprecated it's easy to understand.
I need to get my head round the alternative (OS_SpriteOp). Although I've
been told its easy the last time I looked I didn't find it plain sailing -
I need a good tutorial - I'll do a web search and see what turns up.
A straight forward replacement is simply

SYS "OS_SpriteOp", &00E,, STR$(n)

because SpriteOp &0E is what VDU23,27,1,n| calls behind the scenes. However,
you're no longer limited to numeric names, because you can pass a string
where the STR$(n) is.

If you wished to save the file from the program, instead of using *SSave,
you could add a line

SYS "OS_SpriteOp", &00C,, "MyFileName"

to save the file to the current working directory (or pass a full pathname
instead). SpriteOp &0C is what *SSave calls.

However, you can also create your own areas, which aren't limited by the
16MB restriction of the system sprite area (your file is 15MB, so will be
close to hitting the limit). To do this, you make sure that your Next slot
is big enough to hold the area (so >32768K and a bit extra here), then DIM a
block of memory as the program starts.

REM Set the sprite area size in MB.
sprite_area_size% = 32

REM Get the size in bytes.
sprite_area_size% = sprite_area_size% * 1024 * 1024

REM Allocate the required number of bytes (BASIC allocates one more).
DIM sprite_area% (sprite_area_size% - 1)

REM Put the size of the area into the first word.
sprite_area%!0 = sprite_area_size%

REM The third word must be 16 on initialisation.
sprite_area%!8 = 16

REM Initialise the area.
SYS "OS_SpriteOp", &109, sprite_area%

Note that the call to OS_SpriteOp has &109 instead of &009... The *SNew
command calls

SYS "OS_SpriteOp", &009

but if we add &100 to the SpriteOp number, we can pass our own sprite area
in the second parameter (which is left empty with a double comma in the
first two SYS calls above). The basic SpriteOp codes use the System Sprite
Area; add &100 to the code, and they work on a user sprite area.

This means that the other two calls above become

SYS "OS_SpriteOp", &10E, sprite_area%, STR$(n)

and

SYS "OS_SpriteOp", &10C, sprite_area%, "MyFileName"

They do the same things, but using our sprite area instead. The whole
listing is now

sprite_area_size% = 32
sprite_area_size% = sprite_area_size% * 1024 * 1024
DIM sprite_area% (sprite_area_size% - 1)
sprite_area%!0 = sprite_area_size%
sprite_area%!8 = 16
SYS "OS_SpriteOp", &109, sprite_area%

MODE 1920,1080,32 : OFF
T2=0
n=0
REM Set up rotation variable for square
FOR m=0 TO 6*PI-PI/12 STEP PI/6
REM Set offset for ORIGIN (full circle)
X1=SIN RAD(T2)*100
Y1=COS RAD(T2)*100
REM ORIGIN 1920+X1,1080+Y1
T2+=10
GCOL 3,63 : PROCdraw_square(1920+X1, 1080+Y1, m)
z=INKEY(10)

REM Generate sprite group for animation
MOVE1920-330,1080-330
MOVE1920+330,1080+330
SYS "OS_SpriteOp", &10E, sprite_area%, STR$(n)
n+=1
REM Erase previous square after a delay
GCOL 3,63 : PROCdraw_square(1920+X1, 1080+Y1, m)

NEXT m
SYS "OS_SpriteOp", &10C, sprite_area%, "Sprites"
END

DEF PROCdraw_square(x%, y%, angle)
FOR T = 0 TO 2*PI STEP PI/2
X=x%+SIN(T+angle)*200
Y=y%+COS(T+angle)*200
IF T=0 THEN MOVE X,Y ELSE DRAW X,Y
NEXT T
ENDPROC
--
Steve Fryatt - Leeds, England

http://www.stevefryatt.org.uk/
Richard Ashbery
2020-03-19 21:59:24 UTC
Reply
Permalink
Hi Steve

Just got your latest posting including the listing. I'll have a look
tomorrow. All I can say is many thanks for the work that you and
others have contributed - its certainly helped clear some of my lack
of knowledge of the RISC OS Sprite sytem.

Richard

Matthew Phillips
2020-03-19 08:23:35 UTC
Reply
Permalink
Post by Steve Fryatt
On 17 Mar, Richard Ashbery wrote in message
How should I do this please? Some simple code examples would be
appreciated.
Is there any chance of seeing your current code?
[snip]
As suggested by Chris I've eliminated CLG and substituted the EOR GCOL
3,63. Running program displays an offset square as expected but when the
sprites are saved the offset is missing and clearly absent when viewing
sprites in !Paint. Could this be a problem with the way the program
collects the sprite data?
It sounds like it is. I think Steve was hoping for the complete code: if you
can send the whole lot it will be much easier to tell where the problem is.
The code you copied into the message was just for drawing the graphics. We
definitely need to see how you are saving the sprites as well.

If you cannot share the whole program as it stands, cut it down to
something that still exhibits the same problem and which we can all try
running on our own machines.
--
Matthew Phillips
Durham
Richard Ashbery
2020-03-19 13:34:13 UTC
Reply
Permalink
Post by Richard Ashbery
Post by Richard Ashbery
Post by Steve Fryatt
On 17 Mar, Richard Ashbery wrote in message
How should I do this please? Some simple code examples would
be appreciated.
Is there any chance of seeing your current code?
[snip]
Post by Richard Ashbery
As suggested by Chris I've eliminated CLG and substituted the EOR
GCOL 3,63. Running program displays an offset square as expected
but when the sprites are saved the offset is missing and clearly
absent when viewing sprites in !Paint. Could this be a problem
with the way the program collects the sprite data?
It sounds like it is. I think Steve was hoping for the complete
code: if you can send the whole lot it will be much easier to tell
where the problem is. The code you copied into the message was
just for drawing the graphics.
It is complete honestly Matthew. You've missed the bit where the
sprite group is created.

Ensure System sprites memory is set to 16.384 Mbytes in Tasks; Run
program; Open a TaskWindow; type slist to check that the sprite group
is created; type ssave [filename] to save it to root. Open the sprite
to display the group in !Paint but I'm sure you know all this!!

Although Steve has posted a working modification run his program not
mine and you will see it works correctly.

Apparently my method of generating the sprites is deprecated (went out
with the arc I believe) - I'll have a look at Druck's SWI, OS_SpriteOP
though I suspect I might need help understanding it.

I'll get back to other posters.

Richard
Matthew Phillips
2020-03-19 21:10:00 UTC
Reply
Permalink
Post by Richard Ashbery
Post by Richard Ashbery
Post by Richard Ashbery
Post by Steve Fryatt
On 17 Mar, Richard Ashbery wrote in message
How should I do this please? Some simple code examples would
be appreciated.
Is there any chance of seeing your current code?
[snip]
Post by Richard Ashbery
As suggested by Chris I've eliminated CLG and substituted the EOR
GCOL 3,63. Running program displays an offset square as expected
but when the sprites are saved the offset is missing and clearly
absent when viewing sprites in !Paint. Could this be a problem
with the way the program collects the sprite data?
It sounds like it is. I think Steve was hoping for the complete
code: if you can send the whole lot it will be much easier to tell
where the problem is. The code you copied into the message was
just for drawing the graphics.
It is complete honestly Matthew. You've missed the bit where the
sprite group is created.
I do apologise. I got interrupted when reading your example and when I came
back I forgot that I had meant to check what the VDU command did. I confess
I would have had to look up what it was, though, as I am very unfamiliar with
VDU codes, and, it turns out that VDU 23,27 does not appear in the StrongHelp
VDU commands manual v 2.04 of 12 Nov 2016. Very strange.

In the PRM, the index for "VDU drivers - list of codes" sends me to pages
4-551 and 4-552 where the entry for VDU 23,27 points to page 1-603. That in
turn refers me to the Sprites chapter on page 1-745, which is unhelpful as
the actual information is a dozen pages in, on 1-759 where it explains that
VDU,27,1,n| is equivalent to *SGet n, and finally on page 1-824 we get the
explanation for that command!

If it had been an OS_SpriteOp call I'd have found the right bit of the code
straight away. OS_SpriteOp is better-documented, but I still have to look up
the codes:

SYS"OS_SpriteOp",14,...

SYS"OS_SpriteOp",270,...

SYS"OS_SpriteOp",&10E,...

don't say "Get sprite from cursor" to me, because I usually access all this
stuff through C library routines.
Post by Richard Ashbery
Apparently my method of generating the sprites is deprecated (went out with
the arc I believe) - I'll have a look at Druck's SWI, OS_SpriteOP though I
suspect I might need help understanding it.
What you need is

SYS"OS_SpriteOp",14,0,STR$(n),0

to replace the VDU command. Or possibly

SYS"OS_SpriteOp",14,0,STR$(n),1

if you want to include a palette in the sprite, which VDU 23,27,1,n| does not
seem to do.

You could go further than that and DIM a block of memory in the BASIC so that
you can define your own sprite area rather than the system sprite area. Then
you would not have to mess around altering the system sprite area allocation,
which on most machines these days starts out as 0K.
Post by Richard Ashbery
Ensure System sprites memory is set to 16.384 Mbytes in Tasks; Run program;
Open a TaskWindow; type slist to check that the sprite group is created;
type ssave [filename] to save it to root. Open the sprite to display the
group in !Paint but I'm sure you know all this!!
I don't think I have used *slist or *ssave this millennium -- it was very
helpful to have the extra instructions. Part of the reason I thought that
the program was incomplete was because I couldn't see anywhere that was
saving the sprites to disc. I didn't know you were typing some extra
commands after running it!
--
Matthew Phillips
Durham
Richard Ashbery
2020-03-19 21:40:23 UTC
Reply
Permalink
[snip lots of useful feedback]
Post by Matthew Phillips
Post by Richard Ashbery
Apparently my method of generating the sprites is deprecated
(went out with the arc I believe) - I'll have a look at Druck's
SWI, OS_SpriteOP though I suspect I might need help understanding
it.
What you need is
SYS"OS_SpriteOp",14,0,STR$(n),0
to replace the VDU command. Or possibly
SYS"OS_SpriteOp",14,0,STR$(n),1
I'll have a look. Thanks
Post by Matthew Phillips
You could go further than that and DIM a block of memory in the
BASIC so that you can define your own sprite area rather than the
system sprite area. Then you would not have to mess around
altering the system sprite area allocation, which on most machines
these days starts out as 0K.
That would be a definite improvement over method I've used.
Post by Matthew Phillips
I don't think I have used *slist or *ssave this millennium -- it
was very helpful to have the extra instructions.
It was reasonably well documented in the BBC BASIC Guide and having just
checked the date - wow! that was early in the 1990s. What's surprising
is that it still works :-)

Richard
Derek.Moody
2020-03-17 18:05:48 UTC
Reply
Permalink
Post by Richard Ashbery
I have a simple BASIC program that continuously rotates a square but
offset from the screen centre (1920 x 1080). The screen is cleared for
each rotation step.
I would like to generate a GIF animation that I could use on my
website. I've used the VDU 23,27,1,n| command and then processed the
sprite group through InterGif to create the animated GIF. Dragging GIF
to NetSurf displays the animated square but only rotates around the
screen centre ignoring the offset. How should I do this please? Some
simple code examples would be appreciated.
The 'Trim' option optimises away any transparent edges - see Intergif's help.

It sounds as if you have this wrongly set.

Hth, Cheerio,
--
Loading...