New screen / pixel editor for VIC-20

Basic and Machine Language

Moderator: Moderators

adric22
Vic 20 Hobbyist
Posts: 143
Joined: Fri Mar 11, 2005 6:54 pm

New screen / pixel editor for VIC-20

Post by adric22 »

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.

Image

Image

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
User avatar
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

Post by Mike »

adric22 wrote:8 - Orange
Orange? ... ;)

Would you care to provide a link for beta-testers? :)

Greetings,

Michael
adric22
Vic 20 Hobbyist
Posts: 143
Joined: Fri Mar 11, 2005 6:54 pm

Post by adric22 »

Orange? ... Wink
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.
Would you care to provide a link for beta-testers?
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..

http://galaxy22.dyndns.org/vic20/vicedit

and the source code:

http://galaxy22.dyndns.org/vic20/screenedit.asm
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Thanks for the links, I'll look into these this evening.
adric22 wrote:
Orange? ... :wink:
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.
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.

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.
saehn
Vic 20 Devotee
Posts: 235
Joined: Wed Apr 01, 2009 12:22 pm

Post by saehn »

Wow, cool! I'm going to give this a try, looks interesting.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

adric22 wrote:I certainly can.. however, I warn you now the load/save routine is apparently broken.
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.

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
$C1, and $C2 are used to store the start address, because the values end up there anyway, when SAVE is called. With SAVE, secondary address = 0 is generally the default. With SAVE on tape, secondary address = 1 forces an absolute LOAD, even though a relative LOAD might have been specified! This is mainly used for autostarting tape turbos. Also on tape, secondary address = 2 writes an END OF TAPE marker behind the saved data.

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'. :?
adric22
Vic 20 Hobbyist
Posts: 143
Joined: Fri Mar 11, 2005 6:54 pm

Post by adric22 »

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.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

On a second view, a saw the overwrite only happened in the LOAD routine. However, the given routines are still at your disposal.
adric22 wrote:Everyone complained ...
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.

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.
Leeeeee
soldering master
Posts: 396
Joined: Fri Apr 23, 2004 8:14 am

Post by Leeeeee »

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.

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
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.

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
Hope this is of some use.

Lee.
adric22
Vic 20 Hobbyist
Posts: 143
Joined: Fri Mar 11, 2005 6:54 pm

Post by adric22 »

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.
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.

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.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

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.
adric22 wrote:You've done some interesting tricks in the code you posted. [...] For example, calling an address by loading it into the stack ...
This is how CBM BASIC calls the routines for the commands, for example.

Michael
adric22
Vic 20 Hobbyist
Posts: 143
Joined: Fri Mar 11, 2005 6:54 pm

Post by adric22 »

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:

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
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.
saehn
Vic 20 Devotee
Posts: 235
Joined: Wed Apr 01, 2009 12:22 pm

Post by saehn »

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... :-)

Image

Just a simple three-color conversion with slight editing, classic picture of Sherilyn Fenn.
adric22
Vic 20 Hobbyist
Posts: 143
Joined: Fri Mar 11, 2005 6:54 pm

Post by adric22 »

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... :-)

Image

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.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

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:

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
Greetings,

Michael
Post Reply