New screen / pixel editor for VIC-20
Moderator: Moderators
New screen / pixel editor for VIC-20
In order to draw a nice logo screen for my game, I decided I needed to write a small program to draw on the screen. What this program does is use the "medium" res mode, which is essentially just PETSCII characters but it uses the existing character set to allow painting in a 44x46 "graphics" mode without worrying about which characters to use. It is written entirely in ML and will work on an unexpanded VIC. Below are some screenshots and the instructions to use it.
Right now the program saves in a proprietary binary format that I needed to import into my source code. However, if there is any interest in the community I could see about changing it to output to a plain-text SEQ file and I was even thinking of the possibility of having it output as source-code so it would be even easier to import the screens. Here are the various keys:
Screen Edit for the VIC-20 and C64
F1- Pixel Edit Mode
F3 - Character Edit Mode
F5 - Change background color
F6 - Change border color
L - Load to file called "IMAGE"
S - Save to file called "IMAGE"
C - Change color of character to currently active color without changing character
1 - Black
2 - White
3 - Red
4 - Cyan
5 - Purple
6 - Green
7 - Blue
8 - Orange
SPACE - plot character/pixel
BACKSPACE - Delete character/pixel
RETURN - Select character from chart
CURSOR KEYS - Move around
Right now the program saves in a proprietary binary format that I needed to import into my source code. However, if there is any interest in the community I could see about changing it to output to a plain-text SEQ file and I was even thinking of the possibility of having it output as source-code so it would be even easier to import the screens. Here are the various keys:
Screen Edit for the VIC-20 and C64
F1- Pixel Edit Mode
F3 - Character Edit Mode
F5 - Change background color
F6 - Change border color
L - Load to file called "IMAGE"
S - Save to file called "IMAGE"
C - Change color of character to currently active color without changing character
1 - Black
2 - White
3 - Red
4 - Cyan
5 - Purple
6 - Green
7 - Blue
8 - Orange
SPACE - plot character/pixel
BACKSPACE - Delete character/pixel
RETURN - Select character from chart
CURSOR KEYS - Move around
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: New screen / pixel editor for VIC-20
Orange? ...adric22 wrote:8 - Orange
Would you care to provide a link for beta-testers?
Greetings,
Michael
Well, that is what it looks like to me. I think the manual says yellow, but yellow appears to be available on as an aux color and is number 15.Orange? ... Wink
I certainly can.. however, I warn you now the load/save routine is apparently broken. That is why I didn't post it last night. I won't have time to debug it unil tomorrow. Also the only mode that currently works is the pixel-edit mode. I haven't finished where you can plot actual characters yet..Would you care to provide a link for beta-testers?
http://galaxy22.dyndns.org/vic20/vicedit
and the source code:
http://galaxy22.dyndns.org/vic20/screenedit.asm
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Thanks for the links, I'll look into these this evening.
Colours 8 and 9 are named Orange, and Light Orange respectively, even though Light Orange IMO could much better qualify as Yellow, than 7-"Yellow" would.
Greetings,
Michael
If anything, it more has a greenish tint into it, which would disqualify it as being an orange hue. However, as you presumably have an NTSC system, you could regulate the hue to your liking, anyway.adric22 wrote:Well, that is what it looks like to me. I think the manual says yellow, but yellow appears to be available on as an aux color and is number 15.Orange? ...
Colours 8 and 9 are named Orange, and Light Orange respectively, even though Light Orange IMO could much better qualify as Yellow, than 7-"Yellow" would.
Greetings,
Michael
Last edited by Mike on Mon Oct 26, 2009 11:17 am, edited 1 time in total.
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Right you are. Your save routine defines the X/Y register pair twice, first time with the start, second time with the end address without storing the start address away - this can't work.adric22 wrote:I certainly can.. however, I warn you now the load/save routine is apparently broken.
Furthermore, it isn't necessary to close the file yourselves, the kernal load, and save routines open, and close the file for you indeed.
Here we go:
Code: Select all
SETLFS = $FFBA
SETNAM = $FFBD
LOAD = $FFD5
SAVE = $FFD8
; relative LOAD (secondary address = 0)
LDA #1
LDX #{device-number}
LDY #0
JSR SETLFS
LDA #{length of file name}
LDX #<{location of file name}
LDY #>{location of file name}
JSR SETNAM
LDA #0
LDX #<{forced load address}
LDY #>{forced load address}
JSR LOAD
; absolute LOAD (secondary address = 1)
LDA #1
LDX #{device-number}
LDY #1
JSR SETLFS
LDA #{length of file name}
LDX #<{location of file name}
LDY #>{location of file name}
JSR SETNAM
LDA #0
JSR LOAD
; SAVE (always is absolute, but see below for the relevance of the secondary address)
LDA #1
LDX #{device-number}
LDY #{save secondary address}
JSR SETLFS
LDA #{length of file name}
LDX #<{location of file name}
LDY #>{location of file name}
JSR SETNAM
LDA #<{start address incl.}
STA $C1
LDA #>{start address incl.}
STA $C2
LDA #$C1
LDX #<{end address excl.}
LDY #>{end address excl.}
JSR SAVE
The BASIC LOAD, and SAVE command both use logical channel 1 for their operations, a convention which can be adopted here without problems, as this is the intended use for channel 1.
It might be interesting for your program to provide the import of a whole 2K character set. Also the export of the screen as BASIC program is a very promising idea. I'm currently coding the character editor batch extension for MINIPAINT, which will allow editing all 256 characters. I had planned for them to be presented in the same look as your character selection screen.
All these programs together will give a nice level editor for everything.
Greetings,
Michael
P.S.: Hmm, the main part of this posting should probably also go into 'ROM calls & other tricks'.
Mike, thanks for finding my bug.. I'll see about fixing it when I get home from work. Also, it is ironic about you asking for loading in a full 2K character set. Everyone complained that my game wouldn't run on an unexpanded VIC. So I figured when I was writing this little utility, that I would try to keep it working with the unexpanded version. However, there is no way I could add a full character set and keep it under 3.5K.
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
On a second view, a saw the overwrite only happened in the LOAD routine. However, the given routines are still at your disposal.
Still, you could provide two versions of your editor, one 'lite' version that only works with the PETSCII set, and the 'full' version, which allows importing a 2 K character set. You could do, but don't need to do so. I wouldn't bother even one millionth of a second to write an unexpanded version of MINIPAINT. Where would the code be supposed to go?
Greetings,
Michael
You can savely exclude me from that all-encompassing list. Those who actually may have complained should understand, that not everything can be done in 3.5 K.adric22 wrote:Everyone complained ...
Still, you could provide two versions of your editor, one 'lite' version that only works with the PETSCII set, and the 'full' version, which allows importing a 2 K character set. You could do, but don't need to do so. I wouldn't bother even one millionth of a second to write an unexpanded version of MINIPAINT. Where would the code be supposed to go?
Greetings,
Michael
Last edited by Mike on Mon Oct 26, 2009 12:35 pm, edited 1 time in total.
Your screen clear routine doesn't clear the whole of the colour memory because you don't clear the X register when it's called. Also the routine can be simplified by clearing 512 locations but this menas that six locations will be cleared twice because the screen is only 506 locations long.
Using a lookup and vector table makes the key decoding a lot easier, extra keys can be added or removed just be editing the tables. This is untested but should work.
Hope this is of some use.
Lee.
Code: Select all
; The following routine clears the screen
CLRSCN
LDA CURCOL ; get the colour
LDX #$00 ; clear the index
COLCL1
STA $9600,X ; fill a low page colour byte
STA $96FA,X ; fill a high page colour byte
INX ; increment the index, sets the flags
BNE COLCL1 ; loop if more to do
LDA #$20 ; set [SPACE]
COLCL3
STA $1E00,X ; fill a low page screen byte
STA $1EFA,X ; fill a high page screen byte
INX ; increment the index, sets the flags
BNE COLCL3 ; loop if more to do
RTS
Code: Select all
; test the next key from the table
nextkey
DEY ; else decrement the table index
BPL testkey ; if more keys to test go test them
keyreturn = *-1 ; return address - 1 for RTS from key routines
; wait for a key and call the associated routine
KEYWAIT
JSR $FFE4 ; get a key from the keyboard queue
CMP #$00 ; check if key was returned
BEQ KEYWAIT ; if not go try again
LDY #keyend-keytab-1 ; set the index to the last table entry
testkey
CMP keytab,Y ; compare the key with a table entry
BNE nextkey ; if not a match go do the next key
TAX ; remember the key for the colour routine
; set the return address so that the key routines
; return to KEYWAIT
LDA #>keyreturn ; set the return address high byte
PHA ; push it on the stack
LDA #<keyreturn ; set the return address low byte
PHA ; push it on the stack
TYA ; copy the key index
ASL ; * 2 bytes per word
TAY ; copy back to the index
LDA keycode+1,Y ; get the key code address high byte
PHA ; push it on the stack
LDA keycode,Y ; get the key code address low byte
PHA ; push it on the stack
RTS ; call the code
; table of key codes
keytab
!BYTE $1D ; cursor-right
!BYTE $9D ; cursor-left
!BYTE $91 ; cursor-up
!BYTE $11 ; cursor-down
!BYTE $31 ; Number 1
!BYTE $32 ; Number 2
!BYTE $33 ; Number 3
!BYTE $34 ; Number 4
!BYTE $35 ; Number 5
!BYTE $36 ; Number 6
!BYTE $37 ; Number 7
!BYTE $38 ; Number 8
!BYTE $53 ; S-key
!BYTE $14 ; Backspace
!BYTE $4C ; L-Key
!BYTE $20 ; SPACE
!BYTE $85 ; F1
; !BYTE $86 ; F3
!BYTE $87 ; F5
!BYTE $88 ; F6
!BYTE $43 ; C-KEY
!BYTE $0D ; RETURN
!BYTE $03 ; run/stop - exit
keyend
; table of key code addresses
keycode
!WORD MOVERT-1 ; cursor-right
!WORD MOVELF-1 ; cursor-left
!WORD MOVEUP-1 ; cursor-up
!WORD MOVEDN-1 ; cursor-down
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD docolour-1 ; numbers 1 to 8
!WORD SAVEIMG-1 ; S-key
!WORD DELCH-1 ; Backspace
!WORD LOADIMG-1 ; L-Key
!WORD PLOTCH-1 ; SPACE
!WORD SELCHAR-1 ; F1
; !WORD SOMEHWERE-1 ; F3
!WORD CYCBG-1 ; F5
!WORD CYCBR-1 ; F6
!WORD COLPLOT-1 ; C-KEY
!WORD SELCHAR-1 ; RETURN
!WORD exitprog-1 ; run/stop - exit
; convert the "1" to "8" to a colour and save it
docolour
TXA ; get the key back
SEC ; set carry for subtract
SBC #$31 ; convert "1" to "8" to 0 to 7
STA CURCOL ; save the colour
RTS
: exit by pulling the key code return address and returning to BASIC
exitprog
PLA ; dump the return address low byte
PLA ; dump the return address high byte
RTS
Lee.
I've noticed the bug with the color memory not always being cleared, but I haven't had time to check into it yet.. after all, I only wrote this program yesterday.Leeeeee wrote:Your screen clear routine doesn't clear the whole of the colour memory because you don't clear the X register when it's called. Also the routine can be simplified by clearing 512 locations but this menas that six locations will be cleared twice because the screen is only 506 locations long.
Lee.
You've done some interesting tricks in the code you posted. You can tell I never had any official training in 6502. For example, calling an address by loading it into the stack - I would have never thought of that. I would have used a zero-page address used an indirect JMP. But since I prefer to use JSR, I couldn't figure out how to do that. I had planned to make a better key listening routine, but it started off with just 4 keys and I saw no point.. But then I kept adding more and more.
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Some thoughts to the proposed BASIC export:
You should let the PRINT statements only print one physical line at a time. This way the lines aren't combined into 2, 3, or 4-line logical lines - which might lead to problems, if additional screen output is done later.
For this, only the first 21 characters are printed, and you add the last character of each line with two POKE's into screen RAM, and colour RAM - the addresses given as offset to screen start, and colour start, defined at the begin of the program - but still user customisable.
The last line can be printed the same way, except the PRINT ends with a semicolon, to avoid the screen scrolling.
Finally, you should provide a string Q$=CHR$(34)+CHR$(34)+CHR$(20) as "escape character" to print single double-quotes.
Michael
You should let the PRINT statements only print one physical line at a time. This way the lines aren't combined into 2, 3, or 4-line logical lines - which might lead to problems, if additional screen output is done later.
For this, only the first 21 characters are printed, and you add the last character of each line with two POKE's into screen RAM, and colour RAM - the addresses given as offset to screen start, and colour start, defined at the begin of the program - but still user customisable.
The last line can be printed the same way, except the PRINT ends with a semicolon, to avoid the screen scrolling.
Finally, you should provide a string Q$=CHR$(34)+CHR$(34)+CHR$(20) as "escape character" to print single double-quotes.
This is how CBM BASIC calls the routines for the commands, for example.adric22 wrote:You've done some interesting tricks in the code you posted. [...] For example, calling an address by loading it into the stack ...
Michael
Well, I worked on this some, but didn't have a lot of time.. I used the new routines listed above for load/save and of course modified them to fit better with my code.. Unfortunately, it still doesn't work. Same exact result. I'm not even sure yet if the problem is the load or save routines. I guess I need to pick apart the file saved on the disk to find out if it is all zeros or not. Here is the relevant code:
Any help would be appriciated. I also updated the entire source code to the same link as before. Of course, I guess there is the possibility something has gone wrong with my routine that copies from temporary area to screen RAM. But I tested that feature yesterday by adding a special key to copy the screen back and forth almost like a clip-board effect to make sure it was working before doing the load/save. So I'm pretty sure that works. The only reason I didn't have it save straight from screen-ram is that I wanted the screen and color-memory to be contiguous plus I am storing the color more efficiently since it only uses 4-bits so I'm combining 2 character's color nybbles together so it only takes half as much space. The only other option would have been to write a custom save routine that sent the characters one at a time to the disk drive.
EDIT - I take it back.. I just tried it on my work machine with VICE and it seems to be working. I was using Power20 on my Mac last night and it seemed broken.. I wonder why. I'll have to try again when I get home.
Code: Select all
FILENAME !pet "image"
SETLFS = $FFBA
SETNAM = $FFBD
LOAD = $FFD5
SAVE = $FFD8
LOADFILE ; Uses kernel routine to load temporary screen area from disk.
LDA #$01
LDX #$08 ; Device 8
LDY #$01
JSR SETLFS
LDA #$05
LDX #<FILENAME
LDY #>FILENAME
JSR SETNAM
LDA #$0
JSR LOAD
JSR LOADSCN ; Copy temporary area to screen memory.
RTS
SAVEFILE ; Uses kernel routine to save temporary screen area to disk.
JSR PUTOLD ; Gets the cursor off out of the image before saving.
JSR COPYSCN ; Copy screen to temporary area.
LDA #$01
LDX #$08 ; Device 8
LDY #$00
JSR SETLFS
LDA #$05
LDX #<FILENAME
LDY #>FILENAME
JSR SETNAM
LDA #<SCRTEM ; Temporary area.
STA $C1
LDA #>SCRTEM ; Temporary area.
STA $C2
LDA #$C1
LDX #<SCRTEM+$02F7 ;end of Temporary area.
LDY #>SCRTEM+$02F7 ;end of Temporary area.
JSR SAVE
RTS
EDIT - I take it back.. I just tried it on my work machine with VICE and it seems to be working. I was using Power20 on my Mac last night and it seemed broken.. I wonder why. I'll have to try again when I get home.
Please keep working on this, I like it... we'll be able to achieve some good retro-looking results, even with such harsh restrictions. And this will be very close to the low-res unexpanded VIC graphics mode I've been wanting...
Just a simple three-color conversion with slight editing, classic picture of Sherilyn Fenn.
Just a simple three-color conversion with slight editing, classic picture of Sherilyn Fenn.
Unfortunately.. I think I just went over the memory limit on the unexpanded VIC. I had to move the code lower and use the 3K expansion.. I still have another few routines to write, so i guess this program won't work on the unexpanded VIC after all.saehn wrote:Please keep working on this, I like it... we'll be able to achieve some good retro-looking results, even with such harsh restrictions. And this will be very close to the low-res unexpanded VIC graphics mode I've been wanting...
Just a simple three-color conversion with slight editing, classic picture of Sherilyn Fenn.
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
I've found CPY $FB in the transfer loops. Since $FB is initialised at no place, you most probably meant CPY #$FB.
Unless $FB by chance contains a value >250 you'd be going to lose bytes at the end of the screen.
There are also some redundancies in the routines, for example it isn't necessary to do the 'CPY #0' after 'INY'. The Z flag in set in the intended way already after INY. Also, with 'AND #$0F:CLC:4x ASL', the first two instructions, 'AND #$0F:CLC' are redundant.
Here are streamlined versions of COPYSCN, and LOADSCN:
Greetings,
Michael
Unless $FB by chance contains a value >250 you'd be going to lose bytes at the end of the screen.
There are also some redundancies in the routines, for example it isn't necessary to do the 'CPY #0' after 'INY'. The Z flag in set in the intended way already after INY. Also, with 'AND #$0F:CLC:4x ASL', the first two instructions, 'AND #$0F:CLC' are redundant.
Here are streamlined versions of COPYSCN, and LOADSCN:
Code: Select all
SCREEN = $1E00
COLOUR = $9600
COPYSCN
LDY #0
STY $05
LDA #>COLOUR
STA $06
COP1
LDA SCREEN,Y
STA SCRTEM,Y
LDA SCREEN+250,Y
STA SCRTEM+250,Y
INY
BNE COP1
LDX #0
COP2
LDA ($05),Y
INY
ASL
ASL
ASL
ASL
STA VAR1
LDA ($05),Y
DEY
AND #$0F
ORA VAR1
STA COLTEM,X
INX
CLC
LDA $05
ADC #2
STA $05
BCC COP3
INC $06
COP3
CPX #253
BNE COP2
RTS
LOADSCN
LDY #0
STY $05
LDA #>COLOUR
STA $06
LS1
LDA SCRTEM,Y
STA SCREEN,Y
LDA SCRTEM+250,Y
STA SCREEN+250,Y
INY
BNE LS1
LDX #0
LS2
LDA COLTEM,X
INX
INY
STA ($05),Y
LSR
LSR
LSR
LSR
DEY
STA ($05),Y
CLC
LDA $05
ADC #2
STA $05
BCC LS3
INC $06
LS3
CPX #253
BNE LS2
RTS
Michael