Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

smooth animation with ghostscript?

148 views
Skip to first unread message

luser- -droog

unread,
Nov 2, 2011, 11:52:26 PM11/2/11
to
I was hoping to show this off as a triumph, but it's going to have
to be a plea for assistance. I've got this nifty gradient program
that looks really sharp on xpost (after numerous bugfixes, of
course), but I can't seem to get a smooth animation from gs.

It gets about halfway through the drawing, then stalls and spits
out the middle for a split second. Is there a ghostscript extension
to force an Xflush (or equivalent) to keep the execution in sync
with the rendering?

Regardless, I think this program is pretty hypnotic
even as a series of stills (enough for me to get on the wrong bus,
today). If you preview with -DNOPAUSE, you can see the
"animation", such as it is.

%!
%grad3.ps
%a spinning gradient animation
%run with -dNOPAUSE
%and adjust these sleep arguments if necessary
/smallpause { 50 sleep } def
/pagepause { 500 sleep } def

/vmreclaim where{pop -2 vmreclaim}if
/sleep {
usertime add {
10 {
1 100000 div pop %busy
.1 sin 257 cos atan pop %busy busy
} repeat
dup usertime le {exit}if
} loop pop
} def

/fix 1.5 def
/matrix1 matrix def
/matrix2 matrix def
/matrix3 matrix def
/mats [
{1 exch div neg 1 add 1 matrix1 scale} %horz
{1 exch div neg 1 add 1 exch matrix1 scale} %vert
{1 exch div neg 1 add dup matrix1 scale} %pyramid
{2 index exch 2 exch div neg 1 add dup matrix1 scale
%exch 360 mul 360 exch sub
%exch dup atan fix mul
%exch fix 180 mul mul
%exch 1 sub neg 90 mul fix mul
exch 360 exch div fix mul
matrix2 rotate
exch
matrix3 concatmatrix } %spiral?
] def

% n type makematrix n matrix
/makematrix {
exch dup 3 2 roll % n n type
mats exch get exec
} def


% da polyangle n get exec -
%produce a special-effect rotation angle and its inverse
/polyangle [
{dup -2 div 90 add dup neg} %da 90-da/2 da/2-90%flat bottom
{-90 90} % da -90 90 %pointy top
] def

% angletype n poly -
/poly {
360 1 index div % pa n da
polyangle 4 -1 roll get exec % n da -angle angle
rotate 3 1 roll % -angle n da
1 0 moveto { ?? rotate 1 0 lineto } % -angle n da {...}
dup 0 4 -1 roll put % -angle n {da...}
repeat % -angle
closepath % -angle
rotate %
} def

% n shape -
/shape {
dup 0 eq { pop 0 0 1 0 360 arc fill }{ %zero==infinity
dup 2 mod 1 eq { %odd
dup 1 eq { pop 0 1 moveto 0 -1 lineto %one==vertical line
gsave matrix defaultmatrix setmatrix stroke grestore
}{ %odd&!=1
1 exch poly fill %pointy
} ifelse
}{ %even
dup 2 eq { pop 1 0 moveto -1 0 lineto %two==horiz line
gsave matrix defaultmatrix setmatrix stroke grestore
}{ %even&!=2
0 exch poly fill %flat
} ifelse
} ifelse
} ifelse
} def
%0 1 20 { 300 400 translate 100 100 scale shape showpage } for

% n makeshape {shape}
/makeshape {
[ exch /shape cvx ] cvx
} def


% n ? ? g0 gF makegray grayproc
/makegray {
1 index sub %n ? ? g0 gF-g0
4 index 1 sub div %n ? ? g0 dg/(n-1)
exch setgray %n ? ? dg/(n-1)
%[ exch /add cvx {dup 1 gt{pop 0}if} /exec cvx ] cvx
{ ?? add dup 1 gt {1 sub} if } dup 0 4 -1 roll put
} def

% n matrix shape grayproc agrad -
/agrad { 3 dict begin
/gray exch def /shape exch def /mat exch def
gsave
({ //shape exec smallpause //mat concat
currentgray //gray exec setgray })
token pop exch pop end repeat
grestore
} def

/newpage {
initgraphics
300 390 translate
290 350 scale
} def

[ { 5 2 makematrix 3 makeshape .3 .7 makegray agrad }
{ 1.4 dup scale 50 2 makematrix
.9 dup 3 2 roll scale 4 makeshape 1 0 makegray agrad }
{ 20 0 makematrix 0 makeshape .2 1 makegray agrad }
{ 20 0 makematrix { 0 .5 .5 90 -90 arc fill } 0 1 makegray agrad
20 0 makematrix { 0 -.5 .5 90 -90 arcn fill } 0 1 makegray
agrad }
{ 45 rotate 30 2 makematrix
.8 dup 3 2 roll scale 4 makeshape 1 0 makegray agrad }
] {
newpage
exec
showpage
} clear%forall %some silly gradient "letters"

newpage
3 1 20 { % sh %select a shape 0..inf
3 1 3 { % sh m %select a matrix 0..3
2 copy % sh m sh m
0 .10 1 % sh m sh m st inc max %select a rotation adjustment
{ /fix exch def
20 exch makematrix % sh m sh m mat
3 -1 roll makeshape % sh m m mat shape
.1 .9 makegray % sh m m mat shape gray
agrad % sh m
pagepause
showpage newpage
2 copy % sh m sh m
} for % sh m sh m
} for % sh m sh m
pop pop pop pop
} for

%eof

ken

unread,
Nov 3, 2011, 3:48:04 AM11/3/11
to
In article <2269e738-7978-4e6f-9744-
0d9524...@n13g2000vbv.googlegroups.com>, mij...@yahoo.com says...

> It gets about halfway through the drawing, then stalls and spits
> out the middle for a split second.

Its probably doing garbage collection.

> Is there a ghostscript extension
> to force an Xflush (or equivalent) to keep the execution in sync
> with the rendering?

No, thats not possible with garbage collectors. If I wanted to do this I
would render to a bitm,ap and keep the botmap on screen until the next
bitmap was finished, then swap, and so on.

luser- -droog

unread,
Nov 3, 2011, 5:05:36 AM11/3/11
to
On Nov 3, 2:48 am, ken <k...@spamcop.net> wrote:
> In article <2269e738-7978-4e6f-9744-
> 0d9524764...@n13g2000vbv.googlegroups.com>, mijo...@yahoo.com says...
>
> > It gets about halfway through the drawing, then stalls and spits
> > out the middle for a split second.
>
> Its probably doing garbage collection.

I thought so, too. But this line
/vmreclaim where{pop -2 vmreclaim}if
should disable it.

> > Is there a ghostscript extension
> > to force an Xflush (or equivalent) to keep the execution in sync
> > with the rendering?
>
> No, thats not possible with garbage collectors. If I wanted to do this I
> would render to a bitmap and keep the bitmap on screen until the next
> bitmap was finished, then swap, and so on.

While investigating bitmap devices, I found it:
http://www.ghostscript.com/doc/current/Language.htm#Device

- flushpage -
On displays, flushes any buffered output, so that it is guaranteed
to
show up on the screen; on printers, has no effect.


So change those pause procedures to:

/smallpause {
/flushpage where{pop flushpage}if
20 sleep } def
/pagepause {
/flushpage where{pop flushpage}if
300 sleep } def

And then ghostscript does it perfectly!

Double-buffering seems like a better strategy for fine-tuned results;
although then there's more to strip off before printing. But this does
the
job at at hand.

ken

unread,
Nov 3, 2011, 10:16:55 AM11/3/11
to
In article <9f34c479-2965-4926-9afa-
3da9d2...@o5g2000yqa.googlegroups.com>, mij...@yahoo.com says...

> > Its probably doing garbage collection.
>
> I thought so, too. But this line
> /vmreclaim where{pop -2 vmreclaim}if
> should disable it.

No that just disables external garbage collection, internal still runs.
There is a command to disable it, -dNOGC I think. You could try that.


Ken

luser- -droog

unread,
Nov 3, 2011, 6:41:02 PM11/3/11
to
On Nov 2, 10:52 pm, luser- -droog <mijo...@yahoo.com> wrote:
> ...
> %!
> %grad3.ps
> %a spinning gradient animation
> ...
> /fix 1.5 def
> /matrix1 matrix def
> /matrix2 matrix def
> /matrix3 matrix def
> /mats [
>     {1 exch div neg 1 add  1 matrix1 scale} %horz
>     {1 exch div neg 1 add  1 exch matrix1 scale} %vert
>     {1 exch div neg 1 add  dup matrix1 scale} %pyramid
>     {2 index exch 2 exch div neg 1 add  dup matrix1 scale
>         %exch 360 mul 360 exch sub
>         %exch dup atan fix mul
>         %exch fix 180 mul mul
>         %exch 1 sub neg 90 mul fix mul
>         exch 360 exch div fix mul
>         matrix2 rotate
>         exch
>         matrix3 concatmatrix } %spiral?
>     ] def

I feel really guilty about what I did here. Do you see the
`2 index` at the beginning of the spiral matrix proc?
And then do you see just below where the proc is executed
with just 2 elements on the stack?

> % n type  makematrix  n matrix
> /makematrix {
>     exch dup 3 2 roll % n n type
>     mats exch get exec
>
> } def
> ...

So it's really reach "outside" of its scope, to snag the
shape number from higher up on the stack. So poor early design
led to some undocumented licences which means you can't cut-and-
paste the matrix proc and use it somewhere else. Unless you read this!

> ...

luser- -droog

unread,
Nov 4, 2011, 2:23:13 AM11/4/11
to
While ghostscript's "quirk" with real numbers in for loops is
predictable
(given the binary representation of floating-point numbers) and
easily
worked-around (just add some fraction of the increment to the
threshold);
xpost's issues are far more damning.

In particular it isn't doing the stroke-fill hijack, below,
which ghostscript paints beautifully. I'm probably losing
the path on that `grestore gsave` line.

%!
%grad3a.ps
%a spinning gradient animation
%a shape for all natural numbers
%fades from lightgray through black, and back around again!
%run with -dNOPAUSE -dNOGC
%and adjust these sleep arguments if necessary
/smallpause {
/flushpage where{pop flushpage}if
50 sleep } def
/pagepause {
/flushpage where{pop flushpage}if
1000 sleep } def

/vmreclaim where{pop -2 vmreclaim}if
/sleep {
usertime add {
10 {
1 100000 div pop %busy
.1 sin 257 cos atan pop %busy busy
} repeat
dup usertime le {exit}if
} loop pop
} def

%fix is the "spiral" parameter.
%It should probably be called "phase".
%At 0 and 1 you get a pyramid gradient
%At fractions between (and multiples),
%you get "that much" spiral-effect.
/fix 1.5 def
/matrix1 matrix def
/matrix2 matrix def
/matrix3 matrix def
/mats [
{1 exch div neg 1 add 1 matrix1 scale} %horz
{1 exch div neg 1 add 1 exch matrix1 scale} %vert
{1 exch div neg 1 add dup matrix1 scale} %pyramid
{ 2 index exch % sh n sh n
2 exch div neg 1 add % sh n sh 1-2/n
dup matrix1 scale % sh n sh m1
exch 360 exch % sh n m1 360 sh
dup 3 lt { pop % special case for circles and lines
exch % sh n 360 m1
1 .8 matrix2 scale % make a non-uniform matrix
matrix3 concatmatrix % alter the scaling matrix
matrix1 copy % use that for scaling
exch 2 % sh n m1' 360 2 %/fix 1 def::180 rotate
} if
div fix mul
matrix2 rotate
%exch %---irrelevant?
matrix3 concatmatrix } %spiral?
] def

% shape-no n type makematrix n matrix
/makematrix {
exch dup 3 2 roll % sh n n type
mats exch get exec
} def


% da polyangle n get exec -
%produce a special-effect rotation angle and its inverse
/polyangle [
{dup -2 div 90 add dup neg} % da 90-da/2 da/2-90
%flat bottom
{-90 90} % da -90 90 %pointy top
] def

% angletype n poly -
/poly {
360 1 index div % pa n da
polyangle 4 -1 roll get exec % n da -angle angle
rotate 3 1 roll % -angle n da
1 0 moveto { ?? rotate 1 0 lineto } % -angle n da {...}
dup 0 4 -1 roll put % -angle n {da...}
repeat % -angle
closepath % -angle
rotate %
} def

% n shape -
/shape {
dup 0 eq { pop 0 0 1 0 360 arc fill }{ %zero==infinity, circle
dup 2 mod 1 eq { %odd
dup 1 eq { pop 0 1 moveto 0 -1 lineto %one==vert line
gsave matrix defaultmatrix setmatrix
stroke grestore
}{ %odd&!=1
1 exch poly fill %pointy
} ifelse
}{ %even
dup 2 eq { pop 1 0 moveto -1 0 lineto %two==horiz line
gsave matrix defaultmatrix setmatrix
stroke grestore
}{ %even&!=2
0 exch poly fill %flat
} ifelse
} ifelse
} ifelse
} def
%0 1 20 { 300 400 translate 100 100 scale shape showpage } for

% n makeshape {shape}
/makeshape {
[ exch /shape cvx ] cvx
} def


% n ? ? g0 gF makegray grayproc
% the gray function features "wrap-around"
% so the grayFinal value can be out-of-range,
% but the grays will change according to that
% "velocity", wrapping from 0 to 1 and 1 to 0
% as necessary.
/makegray {
1 index sub %n ? ? g0 gF-g0
4 index 1 sub div %n ? ? g0 dg/(n-1)
exch setgray %n ? ? dg/(n-1)
%[ exch /add cvx {dup 1 gt{pop 0}if} /exec cvx ] cvx
{ ?? add dup 1 gt {1 sub} if dup 0 lt {1 add} if }
dup 0 4 -1 roll put
} def

% n matrix shape grayproc agrad -
/agrad { 3 dict begin
/gray exch def /shape exch def /mat exch def
gsave
({ //shape exec smallpause //mat concat
currentgray //gray exec setgray })
token pop exch pop end repeat
grestore
} def

/newpage {
initgraphics
300 390 translate
290 350 scale
%300 300 scale
} def

[ { 5 2 makematrix 3 makeshape .3 .7 makegray agrad }
{ 1.4 dup scale 50 2 makematrix
.9 dup 3 2 roll scale 4 makeshape 1 0 makegray agrad }
{ 20 0 makematrix 0 makeshape .2 1 makegray agrad }
{ 20 0 makematrix { 0 .5 .5 90 -90 arc fill } 0 1 makegray agrad
20 0 makematrix { 0 -.5 .5 90 -90 arcn fill } 0 1 makegray
agrad }
{ 45 rotate 30 2 makematrix
.8 dup 3 2 roll scale 4 makeshape 1 0 makegray agrad }
] {
newpage
exec
showpage
} clear%forall %some silly gradient "letters"

/strokemat matrix defaultmatrix
3 2 matrix scale matrix concatmatrix def
/oldfill /fill load def
/strokefill {
gsave
oldfill
grestore gsave
1 currentgray sub setgray
strokemat setmatrix
stroke
grestore
newpath
} bind def
/fill {strokefill} def

newpage
0 1 20 { % sh %select a shape 0..inf
3 1 3 { % sh m %select a matrix 0..3
2 copy % sh m sh m
.1 .10 1.01 % sh m sh m st inc max
%select a rotation adjustment
{ /fix exch def
30 exch makematrix % sh m sh m mat
3 -1 roll makeshape % sh m m mat shape
.8 -.5 makegray % sh m m mat shape gray
0 new messages