Poxels splash screen + animation

Basic and Machine Language

Moderator: Moderators

pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

Since I started this thread, I'd like to give my take on this.
The initial idea was to take a small game for the unexpanded vic and add some lines of code to do a splash screen.
In the specific case, since the game was just 1500 bites, I had 2k left to do a better splash screen than the usual "some lines of colored text with some boxing or something".
I think writing basic progs for the unexpanded vic makes sense on its own.
And yes, very friendly and helpful people in this forum :)
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Not quite two dozen lines, but nonetheless... here's pgm2chunky.prg (download). It expects a 44x46 pixels *.pgm file as input, and emits a *.prg file.

A first some initialisations for all possible 2x2 groupings of chunky pixels in string form (G$) and screen code (G%()):

Code: Select all

10 DIMG%(15),S%(1,1),C%(1):POKE36879,27
11 G$="{RVS OFF} {RVS OFF,C=-V,RVS OFF,C=-C,RVS ON,C=-I,RVS OFF,C=-F,RVS OFF,C=-K,RVS ON,C=-B,RVS ON,C=-D,RVS OFF,C=-D,RVS OFF,C=-B,RVS ON,C=-K,RVS ON,C=-F,RVS OFF,C=-I,RVS ON,C=-C,RVS ON,C=-V,RVS ON} ":S%(0,0)=1:S%(1,0)=2:S%(0,1)=4:S%(1,1)=8
12 PRINT"{CLR,BLU}"G$:FORT=0TO15:G%(T)=PEEK(7680+T):NEXT:PRINT"{CLR}";
13 :
Prompts for source and target files. Normally you should use 'invert input', as the background on the VIC-20 is white and foreground is blue:

Code: Select all

14 INPUT"PGM FILE";PF$:INPUT"TARGET";TF$
15 INPUT"INVERT INPUT{2 SPACE}Y{3 LEFT}";YN$:C%(1+(YN$="Y"))=1
16 :
Open the *.pgm file and check that the header (i.e. type and size) is correct, then wait for a key press to proceed:

Code: Select all

17 LF$=CHR$(10):NU$=CHR$(0):Q$=CHR$(34):OPEN2,8,2,PF$+",S,R"
18 GOSUB44:PRINTLI$:IFLI$<>"P5"THENCLOSE2:STOP
19 GOSUB44:PRINTLI$:IFLI$<>"44 46"THENCLOSE2:STOP
20 GOSUB44:PRINTLI$:IFLI$<>"255"THENCLOSE2:STOP
21 PRINT"HEADER OK. PRESS KEY."
22 GETA$:IFA$=""THEN22
23 :
"Clear screen":

Code: Select all

24 FORT=0TO505:POKE7680+T,32:POKE37888+T,0:POKE38400+T,6:NEXT
Read in the *.pgm file and display it on screen, then wait for a key press to proceed:

Code: Select all

25 FORY=0TO45:FORX=0TO43
26 GET#2,A$:P=C%(-(ASC(A$+NU$)>=128)):GOSUB49
27 NEXT:NEXT:CLOSE2
28 GETA$:IFA$=""THEN28
29 :
Write *.prg file from 'shadow' data in the other half of the colour RAM:

Code: Select all

30 OPEN2,8,2,TF$+",P,W":PRINT#2,CHR$(1)CHR$(16);
31 LI=10:GOSUB55:PRINT#2,CHR$(153)Q$"{CLR,BLU}"Q$";"NU$;:I$=""
32 FORY=0TO22:LI=11+Y:GOSUB55:PRINT#2,CHR$(153)Q$;
33 FORX=0TO21:IFY=22THENIFX=21THEN37
34 H$=MID$(G$,2*(PEEK(37888+Y*22+X)AND15)+1,2)
35 PRINT#2,RIGHT$(H$,1-(LEFT$(H$,1)<>LEFT$(I$,1)));
36 I$=H$
37 NEXT:PRINT#2,Q$";"NU$;
38 NEXT
39 LI=34:GOSUB55
40 PRINT#2,CHR$(151)"8185,"MID$(STR$(G%(PEEK(38393)AND15)),2)":";
41 PRINT#2,CHR$(151)"38905,6"NU$;
42 GOTO57
43 :
Read in a line of the *.pgm file header:

Code: Select all

44 LI$=""
45 GET#2,A$:IFA$<>LF$THENLI$=LI$+A$:GOTO45
46 IFLEFT$(LI$,1)="#"THEN44:REM IGNORE COMMENT LINES
47 RETURN
48 :
Draw a chunky pixel using the other half of the colour RAM as 4-bit store:

Code: Select all

49 IFP=0THENRETURN
50 AD=22*INT(Y/2)+INT(X/2)
51 POKE37888+AD,PEEK(37888+AD)ORS%(XAND1,YAND1)
52 POKE7680+AD,G%(PEEK(37888+AD)AND15)
53 RETURN
54 :
Write beginning of a BASIC line (a dummy link-pointer and the line number):

Code: Select all

55 PRINT#2,LF$LF$CHR$(LI)NU$;:RETURN
56 :
Add a wait for key press at the end of the *.prg output file:

Code: Select all

57 LI=35:GOSUB55:PRINT#2,CHR$(161)"A$:"CHR$(139)"A$"CHR$(178)Q$Q$CHR$(167);
58 PRINT#2,MID$(STR$(LI),2)NU$NU$NU$;:CLOSE2:END
Here's an example picture (download). The resulting code looks like this:

Code: Select all

10 PRINT"{CLR,BLU}";
11 PRINT"{RVS OFF,C=-D,C=-B,RVS ON,6 SPACE,C=-F,RVS OFF,8 SPACE,RVS ON} {C=-K,2 SPACE,RVS OFF,C=-K}";
12 PRINT" {RVS ON,C=-B,4 SPACE,C=-F} {RVS OFF,C=-K,5 SPACE,C=-D,2 SPACE,RVS ON} {RVS OFF,C=-V,RVS ON,2 SPACE,RVS OFF,C=-K}";
13 PRINT"{C=-C,RVS ON,C=-B,4 SPACE,C=-F} {RVS OFF,C=-I,C=-F,3 SPACE,RVS ON,C=-V,RVS OFF,C=-B,2 C=-I,RVS ON,C=-C,RVS OFF,C=-V,RVS ON,2 SPACE,C=-C}";
14 PRINT"{RVS OFF,C=-C,RVS ON,C=-B,6 SPACE,C=-F,2 SPACE,RVS OFF,2 SPACE,C=-D,RVS ON} {C=-D} {RVS OFF,2 C=-K,RVS ON,2 SPACE,C=-C}";
15 PRINT"{RVS OFF,C=-C,RVS ON,C=-B,4 SPACE,C=-F,4 SPACE,RVS OFF,C=-K} {RVS ON,C=-K,2 C=-C,2 C=-D,RVS OFF,C=-K,RVS ON,C=-V} {C=-C}";
16 PRINT"{RVS OFF} {RVS ON,C=-B,7 SPACE,RVS OFF,C=-K,RVS ON} {C=-C,RVS OFF,2 SPACE,RVS ON,C=-I,RVS OFF,C=-V} {RVS ON,C=-K,C=-F,C=-K} {C=-C}";
17 PRINT"{RVS OFF} {RVS ON,C=-V,7 SPACE,2 C=-F} {RVS OFF,5 SPACE,C=-D,RVS ON,C=-F,C=-K,2 SPACE}";
18 PRINT"{RVS OFF,C=-C,RVS ON,C=-V,6 SPACE,C=-D,RVS OFF,C=-B,RVS ON,C=-F} {RVS OFF,5 SPACE,C=-D,RVS ON} {C=-K,2 SPACE}";
19 PRINT"{RVS OFF} {RVS ON,C=-V,6 SPACE,RVS OFF,C=-C,C=-D,RVS ON,C=-F} {RVS OFF,6 SPACE,RVS ON} {C=-C,2 SPACE}";
20 PRINT"{RVS OFF} {RVS ON,C=-V,5 SPACE,C=-C,RVS OFF,C=-V,C=-D,RVS ON,2 SPACE,RVS OFF,5 SPACE,C=-C,RVS ON} {C=-C,2 SPACE}";
21 PRINT"{RVS OFF} {RVS ON,C=-V,6 SPACE,RVS OFF,2 C=-B,RVS ON} {C=-C,RVS OFF,5 SPACE,C=-C,RVS ON} {C=-C} {C=-D}";
22 PRINT"{RVS OFF} {RVS ON,C=-V,7 SPACE,C=-K,2 SPACE,RVS OFF,C=-F,4 SPACE,C=-C,RVS ON} {C=-C} {C=-D}";
23 PRINT"{RVS OFF} {RVS ON,C=-V,7 SPACE,RVS OFF,C=-B,RVS ON,2 SPACE,RVS OFF,C=-K,4 SPACE,C=-C,RVS ON,2 SPACE,C=-F,C=-D}";
24 PRINT"{RVS OFF} {RVS ON,C=-V,7 SPACE,RVS OFF,C=-B,RVS ON,C=-F} {RVS OFF,C=-V,4 SPACE,C=-C,RVS ON,4 SPACE}";
25 PRINT"{RVS OFF} {RVS ON,C=-F,8 SPACE,RVS OFF,C=-B,RVS ON} {RVS OFF,5 SPACE,C=-D,RVS ON,2 SPACE,C=-V,C=-C}";
26 PRINT"{RVS OFF} {RVS ON,12 SPACE,C=-K,C=-C,RVS OFF,2 SPACE,RVS ON,C=-K,3 SPACE,C=-C}";
27 PRINT"{RVS OFF} {RVS ON,C=-V,10 SPACE,2 C=-D,RVS OFF,3 SPACE,RVS ON,C=-V,3 SPACE,C=-C}";
28 PRINT"{RVS OFF} {RVS ON,11 SPACE,RVS OFF,C=-K,RVS ON,C=-B,RVS OFF,3 SPACE,RVS ON,4 SPACE,RVS OFF,C=-K}";
29 PRINT" {RVS ON,C=-V,10 SPACE,C=-I,RVS OFF,C=-V,2 SPACE,RVS ON,C=-K,4 SPACE,RVS OFF,C=-K}";
30 PRINT" {RVS ON,C=-V,10 SPACE,RVS OFF,C=-V,3 SPACE,RVS ON,5 SPACE,RVS OFF,C=-K}";
31 PRINT" {RVS ON,C=-V,10 SPACE,RVS OFF,C=-V,2 SPACE,C=-D,RVS ON,5 SPACE,RVS OFF,C=-K}";
32 PRINT" {RVS ON,C=-V,10 SPACE,C=-D,RVS OFF,C=-D} {C=-D,RVS ON,5 SPACE,RVS OFF,C=-K}";
33 PRINT" {RVS ON,C=-V,10 SPACE,C=-D,RVS OFF,2 SPACE,C=-D,RVS ON,5 SPACE}";
34 POKE8185,236:POKE38905,6
35 GETA$:IFA$=""THEN35
Last edited by Mike on Thu Feb 20, 2014 5:36 pm, edited 1 time in total.
pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

Awesome! :-)
Thanks very much Mike!
PhilRanger
Vic 20 Hobbyist
Posts: 143
Joined: Thu Aug 25, 2011 10:04 am

Post by PhilRanger »

Superb Mike. I'll take time to digest the source code and I'm sure I'll learn a lot!
Phil Ranger
-------------
"Don't eat the trees 2" for the VIC 20 : http://www.box.net/shared/u398kj0nr0lkauzm1k67
on line: http://www.mdawson.net/vic20chrome/vic2 ... otrees.prg
pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

Just for fun I modified Mike's program to make poxel animations. About 4fps are achievable.

Here is a sample output:

http://www.opbyte.it/vic20/megaman.prg

16k expansion needed (24 frames, about 800 bytes per frame)
matsondawson
The Most Noble Order of Denial
Posts: 343
Joined: Fri May 01, 2009 4:44 pm

Post by matsondawson »

pallas wrote:Just for fun I modified Mike's program to make poxel animations. About 4fps are achievable.

Here is a sample output:

http://www.opbyte.it/vic20/megaman.prg

16k expansion needed (24 frames, about 800 bytes per frame)
Cool, a bit of runlength compression on that with diffs between frames you could be in 6fps land there!
Last edited by matsondawson on Wed Mar 13, 2013 3:12 pm, edited 1 time in total.
pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

matsondawson wrote:Cool, a bit of runtime compression on that with diffs between frames you could be in 6fps land there!
Yes, and a simple optimization for both size and speed would be to put two drawing lines on a single line of code (so half the print instructions).
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

pallas wrote:a simple optimization [...] would be to put two drawing lines on a single line of code
The converter optimizes already a lot by leaving out {RVS ON} and {RVS OFF} control characters, when they're not necessary. But in the worst case, a single line could still contain 22 control characters, 22 printed characters, 2 quotes, 1 semicolon, and 8 characters for the line number and PRINT, i.e. 55 characters in total.

If you put two lines into one PRINT, the converter could do that, but there are chances the LISTed line exceeds the 88 character limit. You couldn't anymore edit the line then. I suppose the speed increase would also be negligible.
pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

Mike wrote:The converter optimizes already a lot by leaving out {RVS ON} and {RVS OFF} control characters, when they're not necessary. But in the worst case, a single line could still contain 22 control characters, 22 printed characters, 2 quotes, 1 semicolon, 8 characters for the line number and PRINT, i.e. 55 characters in total.
There is another solution. If writing the whole line of 22 chars, it's just a single stream of characters which could be split into arbitrary length prints. We could optimize it to the lowest number of prints and by using 88 or 87 chars per line.
If I have some free time I will try to build the chars string and, when it reaches 88, write the line and trim the string.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Don't bother. I just checked the speed difference between a screen built up from single line PRINTs (without any control characters) and triple-line PRINTs (also without control characters, the last PRINT doing two lines), each done in a loop 100 times:

1 line PRINTs: 1158 jiffies,
3 line PRINTs: 1086 jiffies.

That's a speed increase by only 6%.

With single line PRINTs already, nearly all of the time is spent in the actual string output routine. The interpreter needs just a fraction of that time to advance to the next line and process the next PRINT token.
pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

True. Difference in speed is minimal.
I had a chance to try it out anyways (I like to optimize programs) and the good thing is a 25% save in size, so I was able to fit 6 more frames in the same 16K ram.
Here is the result:

http://www.opbyte.it/vic20/megaman.prg

Here is the generation prg, which can be used to create splash screens with a single frame or animations. Needs 8K, just configure the first 2 lines and run:

http://www.opbyte.it/vic20/pgm2poxelanim.prg
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

When I wrote about the 88 character limit, I didn't mean the character count inside the quotes, or the length of the tokenized line in memory, but the total length of the BASIC line when LISTed.

Now most of the lines exceed that limit and you can't edit them anymore. :(

And, please, what's the reason the converter needs 8K now? The original runs fine in unexpanded memory. (If the sole reason was, so you could compile it, you can run that kind of programs also with 'no speed limit' in VICE ...) Even though you corrected the addresses for the screen memory, you forgot to exchange the addresses for the two colour RAM halves as well.
User avatar
Kweepa
Vic 20 Scientist
Posts: 1315
Joined: Fri Jan 04, 2008 5:11 pm
Location: Austin, Texas
Occupation: Game maker

Post by Kweepa »

Nice work, Mike and pallas!
pallas
Vic 20 Devotee
Posts: 212
Joined: Mon Dec 24, 2012 2:38 am

Post by pallas »

Mike wrote:When I wrote about the 88 character limit, I didn't mean the character count inside the quotes, or the length of the tokenized line in memory, but the total length of the BASIC line when LISTed.

Now most of the lines exceed that limit and you can't edit them anymore. :(

And, please, what's the reason the converter needs 8K now? The original runs fine in unexpanded memory. (If the sole reason was, so you could compile it, you can run that kind of programs also with 'no speed limit' in VICE ...) Even though you corrected the addresses for the screen memory, you forgot to exchange the addresses for the two colour RAM halves as well.
The program counts the chars of the line before writing to file. It check the length without the final double quotes and semicolon to be no more than 86. If it doesn't work as expected, there might be a bug.
The reason the program is set to run on the expanded Vic is just the convenience of not having to change the settings of vice between generation and display.
The colour ram is wrong, I know that, but it works.
There are many other things that could be fixed or done better: the code is messy.
But if people intend to use it, I'll fix and make it better :-)
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

pallas wrote:The program counts the chars of the line before writing to file. It check the length without the final double quotes and semicolon to be no more than 86. If it doesn't work as expected, there might be a bug.
Here's how a LISTed line with 87 characters in total looks (i.e. line number, blank, PRINT, 2 quotes, semicolon and payload):

Code: Select all

10 PRINT"AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA";
Those are only 76 A's. With a three-digit line number, there's one A less available.

Regardless, for my original chunky pixel converter I surely didn't strive for perfection, it was just a quick hack too see if it could be done as I had stated earlier in this thread. With machine language, all these restrictions won't apply anymore: you can easily build a screenful of chunky pixels at a frame rate of 50 or 60 Hz, from packed data (putting two 2x2 chunky pixel groups into a byte gives 253 bytes per screen) and thus fit 50+ animation phases into RAM. And apply run length encoding, or whatever ...

Have fun!
Post Reply