Log In  


User @taxicomics started a thread compiling fades and transitions code snippets https://www.lexaloffle.com/bbs/?tid=148256

I though I'd add my screen dissolve effect, base on a 14 bit variation of the xorshift algorithm
https://en.wikipedia.org/wiki/Xorshift

The shift parameters used are >>3 <<1 >>4 . It's not good as a random generator, but that's a property I don't care about in this context, and amongst the many triplets that give the maximum cycle length needed to progressively blacken every screen pixel, it's the easiest to remember : 314 is the start of pi and 14 is the number of bits.

It works as expected for the first 2/3 of the screen, but after that, the CPU load goes over 100%, and the frame skips makes the animation end in awful looking flicker :

function fade(progress)
 pset(0,0,0)
 local s=1
 while progress>0 do
  s^^=s\8
  s^^=s<<1
  s&=0x3fff
  s^^=s\16
  pset(s\128,s%128,0) 
  progress-=0x0.0004
 end
end

extcmd("rec")
for p=0,1,1>>7 do
 cls(7)
 fade(p)
 flip()
end
extcmd("video")

I've only used it for fade outs, so without screen clears, I just had to go pset a few pixels every frame, but with the versatility of the fade(progress) approach, every pixel has to be redrawn every frame, in case it's used for a fade in for example.
I'm stuck at the moment. Any advice ?



Turns out the frame skips don't look as bad when using the _draw approach.
It's still not great.
I've tried different variations of the code, but still have the CPU around 130% when progress is maximum.

I tried to remove the calculation of s to see how much of the cpu is taken by the pset statements, and it peaks at around 85%, so current s caluclations take 45% cpu max, and should take 15% at most. (ideally faster than that, as in the example, the only "client" computation of the screen image before darkening is a call to cls )
I need to do the s computation 3 times as fast, or find a faster alternative to pset...

function fade(progress)
 progress=mid(0,progress,1)
 if(progress==0) return
 pset(0,0,0)
 local s=1

 while progress>0 do
  s^^=s>>3
  s&=0x3fff
  s^^=s<<1
  s&=0x3fff
  s^^=s>>4
  s&=0x3fff
  pset(s\128,s%128,0) 
  progress-=0x0.0004
 end
end

function _init()
 p=0
 step=1>>7
 snap_start=false
 snap_finish=false
end

function _draw()
 cls(7)
 fade(p)
 print(stat(1),54,62,8)
 if (p==0) then
   if not snap_start then
    snap_start=true
    extcmd("rec")
   elseif not snap_end then
    snap_end=true
    extcmd("video")
   end
 end

end

function _update()
 p+=step
 if p%1==0 then 
   step*=-1 
 end
end

1

using https://fabiensanglard.net/fizzlefade/ as reference I got something that clocks at 3-7% cpu depending on the number of pixels touched per frame

(nothing invented here - just ported C code)

Cart #fepekezima-0 | 2025-04-15 | Code ▽ | Embed ▽ | No License
1


@freds72
Thanks for your answer. It's a working standalone dissolve effect that is very similar to mine : a seed based sequence that iterates screen coordinates.
Unfortunately, it requires the screen not to be cleared between frames so the previous cleared pixels stay black, and that's not compatible with the approach @taxicomics is looking for. Once I convert it to the fade(progress) that need to paint up to 100% of the screen in black during a single frame, I get the same kind of CPU load. Another drawback of the transition function is that it's not tailored to the pico8 screen so pixels have to be cleared multiple times before the entire screen is black, making the CPU cost even higher (the test cart just does 16384 calls to pset at most, so no chance to blacken the full screen) . What I wasn't aware of is that spr(0,0,0,16,16) is very fast. I think the solution will be to pre-compute a 50% darkened sprite sheet beforehand in high memory as a kind of checkpoint, and apply that with spr(0,0,0,16,16) as a starting point if the progress is greater than 50%.

Cart #kokufimato-0 | 2025-04-16 | Code ▽ | Embed ▽ | No License


1

Cart #sprfadeprogress_s-0 | 2025-04-16 | Code ▽ | Embed ▽ | No License

It has some regularity, but is lightweight.
It just uses sset instead of pset and pastes sprites over the entire screen.
I used four sprites, but I think you can create more irregularity by increasing the number.

(I borrowed your random number generator and tweaked it.)


1

@shiftalow, Nice one. It does feel somewhat grid based, but not fully regular, a bit like sand trickling down a sieve. You should definitely post it there :
https://www.lexaloffle.com/bbs/?tid=148256
There's one caveat with this code : you use srand() to get consistent random sequences for the progressive effect, but that might be a problem for the games that use your fade : the randomness that follows becomes fixed.
Maybe peek the seed before calling srand() and poke it back before exiting the function ?

I'll mark the problem as solved : between your solution and the idea I got from freds72 example, I'm not stuck any more.
Thank you both.



[Please log in to post a comment]