Something is better than nothingFill Area
Flip Screen X and Y
The drawing program to rule them all
Moderator: MaxCoderz Staff
Okay, I will paste the code here.
**EDIT: This code should not have the error mentioned previously. The problem was probably the use of saferam2.
Note that the code uses ion.inc, and #defines TI83P but does NOT use an assembly shell. You must assemble it for the 83+, not with the ion batch file, unless you remove the #define from the second line. The functions in this program do not use the last row of the screen. This was intended to make it easy to manipulate pictures which could be saved in Pic variables.
The keys are a bit hard to remember, but I'll list as many as I can:
EDIT: Also notice that pressing/holding the ON key has various functions scattered through the program.
EDIT(2): Just so you don't have to figure it out: The floodfill uses a buffer the size of the screen to store points which haven't been looked at yet. It stores points which have been flooded, ignores points which were of the boundry color. Also, the screen is inverted conditionally to ease the actual routine's job. Pressing a key while the floodfill is executing will show this.
**EDIT: This code should not have the error mentioned previously. The problem was probably the use of saferam2.
Code: Select all
.nolist
#define TI83P
#include "ion.inc"
#ifdef TI83P
.org progstart-2
.db $BB,$6D
#else
.org progstart
#endif
cur_y =saferam3
cur_x =cur_y+1
cur_byte =cur_x+3
flood_y =cur_byte+2
bcall(_indicatorOff)
main:
bcall(_copygbuf)
in a,(4)
bit 3,a
jr z,main_input
mainloop:
halt
halt
halt
halt
main_input:
ld b,0
call getkport
inc a
jr z,mainloop
ld b,%11111101
call getkport
bit 6,a
ret z
ld de,main
push de
ld b,%11111110
call getkport
b_up:
bit 3,a
jr nz,b_down
ld de,uprow
push de
b_down:
bit 0,a
jr nz,b_left
ld de,downrow
push de
b_left:
bit 1,a
jr nz,b_right
ld de,leftrow
push de
b_right:
bit 2,a
jr nz,group_I
ld de,rightrow
push de
group_I:
ld b,%10111111
call getkport
s_left:
bit 3,a
jr nz,s_right
ld de,leftbit
push de
s_right:
bit 2,a
jr nz,b_flip
ld de,rightbit
push de
b_flip:
bit 0,a
jr nz,b_mirror
ld de,flip
push de
b_mirror:
bit 1,a
jr nz,b_input
ld de,mirror
push de
b_input:
bit 4,a
jr nz,b_invert
ld de,floodinput
push de
b_invert:
ld b,%11101111
call getkport
bit 7,a
jp nz,end_main
ld de,invert
push de
end_main:
ret
getkport: ;Read a key from group b
ld a,$FF
out (1),a
ld a,b
nop \ nop
out (1),a
nop \ nop
in a,(1)
ret
uprow:
ld hl,gbuf
ld de,saferam1
ld bc,12
ldir
ld hl,gbuf+12
ld de,gbuf
ld bc,768-12
ldir
ld hl,saferam1
ld de,gbuf+767-23
ld bc,12
ldir
ret ;End of this routine
downrow:
ld hl,gbuf+767-23
ld de,saferam1
ld bc,12
ldir
ld hl,gbuf+767-24
ld de,gbuf+767-12
ld bc,768-12
lddr
ld hl,saferam1
ld de,gbuf
ld bc,12
ldir
ret ;End of this routine
leftrow:
ld hl,gbuf-12
ld b,64
l_row_loop:
push bc
ld de,12
add hl,de
ld a,(hl)
dec de
add hl,de
rla
ld b,12
l_byte_loop:
rl (hl)
dec hl
djnz l_byte_loop
inc hl
pop bc
djnz l_row_loop
ret ;End of this routine
rightrow:
ld hl,gbuf+767+12
ld b,64
r_row_loop:
push bc
ld de,-12
add hl,de
ld a,(hl)
inc de
add hl,de
rra
ld b,12
r_byte_loop:
rr (hl)
inc hl
djnz r_byte_loop
dec hl
pop bc
djnz r_row_loop
ret ;End of this routine
leftbit:
ld hl,gbuf+767-12
ld bc,768-12
ld a,(gbuf)
rla
l_bit_loop:
rl (hl)
cpd
jp pe,l_bit_loop
ret ;End of this routine
rightbit:
ld hl,gbuf
ld bc,768-12
ld a,(gbuf+767-12)
rra
r_bit_loop:
rr (hl)
cpi
jp pe,r_bit_loop
ret ;End of this routine
mirror:
ld hl,gbuf-6
ld b,63
mirrorloop:
ld de,6
add hl,de
ld de,11
ex de,hl
add hl,de
ex de,hl
push bc
ld b,6
rowloop:
ld a,(de)
ld c,(hl)
push de
push bc
ld b,8
flipbyte:
srl a
rl d
srl c
rl e
djnz flipbyte
ld a,e
pop bc
ld c,d
pop de
ld (de),a
ld (hl),c
inc hl
dec de
djnz rowloop
pop bc
djnz mirrorloop
ret ;End of this routine
flip:
ld hl,gbuf-13
ld de,gbuf+767-12
ld b,31
fliploop:
push bc
ld bc,24
add hl,bc
ld b,12
switch:
ld a,(de)
ldd
inc hl
ld (hl),a
dec hl
djnz switch
pop bc
djnz fliploop
ret ;End of this routine
floodinput:
ld hl,31+(47*256)
jr store_point
cursor:
halt
halt
cursor_input:
halt
halt
ld b,0
call getkport
inc a
jr z,cursor ;no keys pressed-->idle
on_wait:
in a,(4)
bit 3,a
jr z,on_wait
ld hl,(cur_y)
ld b,%10111111
call getkport
bit 5,a
jr z,one_invert ;[2nd] was pressed
push af
call draw_point
pop af
jr pixelnorm
one_invert:
halt
halt
halt
pixelnorm:
ld hl,(cur_y)
bit 6,a
ret z ;[MODE] was pressed
bit 2,a
push hl
call z,input ;[ZOOM] was pressed
pop hl
ld b,%11111110 ;checking arrow keys
call getkport
up: bit 3,a
jr nz,down
dec l
down: bit 0,a
jr nz,c_left
inc l
c_left: bit 1,a
jr nz,c_right
dec h
c_right:
bit 2,a
jr nz,check_y
inc h
check_y:
ld a,l
cp 63
jr c,check_x
cp 159
ld l,0
jr c,check_x
ld l,62
check_x:
ld a,h
cp 96
jr c,store_point
cp 175
ld h,0
jr c,store_point
ld h,95
store_point:
ld (cur_y),hl
ld de,cursor_input
push de
draw_point:
ld a,h
call getpixel
xor (hl)
ld (hl),a
bcall(_copygbuf)
ret
input:
ld a,h
call getpixel
;Flood fill the screen
;Input: hl=byte where pixel is on the buffer
; a=bitmask for pixel
;Output: Screen is flooded from starting point
floodfill:
push hl
ld hl,saferam1 ;clearing saferam1
ld de,saferam1+1 ;
ld bc,767 ;
ld (hl),0 ;
ldir
pop hl
ld b,a ;save mask to b
xor (hl) ;invert the origin pixel
ld (hl),a ;
ld de,saferam1-gbuf ;move to the backupscreen
add hl,de ;
ld (hl),b ;set the corresponding bit
sbc hl,de ;move back to the screen buffer
ld a,b ;check the status of the first pixel
and (hl) ;
jr nz,floodstart ;if the pixel was already white, don't invert the screen
call invert ;this guarantees that we are only changing pixels from white to black, requires less code
xor a ;make the flood routine fall through if it has to change the screen back
ld (endfill),a ;(ret-->nop)
floodstart:
ld hl,0
ld (cur_byte),hl
floodloop:
xor a ;searching for 0s, also clears carry
ld hl,768
ld bc,(cur_byte)
sbc hl,bc ;(bc=bytes from start, hl=bytes from end) of saferam1
push bc
ld b,h
ld c,l
pop hl ;bc=counter=bytes from end
ld de,saferam1 ;move hl to be pointer
add hl,de ;
findbyte1:
cpi
jr nz,findbit ;if the byte had a bit set, find it
jp pe,findbyte1 ;search bytes again if bc not 0
ld hl,saferam1
ld bc,(cur_byte)
inc bc
findbyte2:
cpi
jr nz,findbit
jp pe,findbyte2
jp endfill ;no bits were found, exit the routine
findbit:
dec hl
ld a,(hl)
ld b,%00000001 ;the mask for the pixel will be in b
ld c,$FF ;counts the number of pixels from the left in the byte
findbitloop:
inc c
rrc b
rlca
jr nc,findbitloop ;if the leftmost bit wasn't set, continue looking for a bit
ld a,b ;reset the bit in the backupscreen so it won't be found again
xor (hl) ;
ld (hl),a ;
ld de,saferam1
sbc hl,de ;set hl to be the offset, not an absolute pointer
ld (cur_byte),hl
ld a,12 ;dividing by the # of bytes in a row
push bc
bcall(_divhlbya)
pop bc
rlca ;multiply a by 8
rlca ;
rlca ;
add a,c ;a=x coordinate
ld c,a ;save x coordinate in c
ld a,l ;a=y coordinate
ld (flood_y),a ;save the y coordinate
above:
or a ;check to see if the point is at the top of the screen
jr z,below ;skip above if it is
ld hl,(cur_byte) ;restore hl as the offset
ld de,gbuf-12 ;make hl point to the above byte
add hl,de ;
ld a,b ;using the same mask for the above pixel
and (hl)
jr nz,below ;if the pixel doesn't need to be set, skip
call setbits ;set the pixel on the screen and set a bit in saferam1
below:
ld a,(flood_y)
cp 62
jr nc,left ;make sure it isn't already at the bottom...
ld hl,(cur_byte)
ld de,gbuf+12 ;going to next row...
add hl,de
ld a,b ;same mask
and (hl)
jr nz,left ;if it's already set, don't set it
call setbits
left:
ld a,c
or a
jr z,right ;make sure it's not on the left
ld hl,(cur_byte)
ld de,gbuf ;we want to check the same byte
add hl,de
ld a,b ;copying the mask into a
rlca ;moving the current pixel right one
jr nc,sameleft ;if the set bit carried, the current byte changed
dec hl ;move left one byte
sameleft:
and (hl)
jr nz,right
rlc b ;change the actual mask
call setbits
rrc b ;set the mask back to how it was
right:
ld a,c
cp 95
jr nc,endfloodloop ;if on the right side...
ld hl,(cur_byte)
ld de,gbuf ;same byte as original
add hl,de
ld a,b
rrca
jr nc,sameright ;don't change the current byte if the bit didn't carry
inc hl
sameright:
and (hl)
jr nz,endfloodloop
rrc b ;make the final change to the actual mask
call setbits
endfloodloop:
ld b,0
call getkport
inc a
jr z,noupdate ;if no key was pressed, don't update the screen
bcall(_copygbuf)
noupdate:
in a,(4)
bit 3,a
jp nz,floodloop ;look for another set bit in saferam1
endfill: ret
ld a,%11001001;C9 ;Put an end on the routine again
ld (endfill),a ;(nop-->ret)
invert:
ld hl,gbuf
ld bc,768-12
invertloop:
ld a,(hl)
cpl
ld (hl),a
cpi
jp pe,invertloop
ret
setbits:
ld a,b ;mask into a
or (hl) ;set the pixel on the screen
ld (hl),a ;
ld de,saferam1-gbuf ;moving to the backupscreen
add hl,de ;
ld a,b ;mask into a again
or (hl) ;set the bit
ld (hl),a ;
ret
getpixel:
ld h,0
ld d,h
ld e,l
add hl,hl
add hl,de
add hl,hl
add hl,hl ;hl=l*12
ld e,a
srl e ;dividing by 8 to get the bytes from left
srl e ;
srl e ;
add hl,de ;turn offset into absolute
ld de,gbuf ;
add hl,de ;hl points to byte in screen buffer
and %00000111 ;we want the bit offset in a
ld b,a ;b=rotations to get mask
ld a,%10000000 ;start on the msbit
ret z ;if the leftmost bit is needed, no rotation necessary
loop:
rrca
djnz loop
ret
.end
.end
The keys are a bit hard to remember, but I'll list as many as I can:
- -=In primary mode=-
Arrow keys: Scroll screen (wraps)
GRAPH/TRACE: Flip/Mirror screen
WINDOW/ZOOM: Scroll screen (entire buffer) one bit left or right. Wraps to next line, top to bottom, bottom to top.
X,T,theta,n: Invert screen
Clear: Quit from primary mode
Y=: Switch to cursor mode
-=In cursor mode=-
2nd: Invert pixel
ZOOM: Flood fill from selected pixel. Returns to primary mode when finished.
MODE: Quit to primary mode
EDIT: Also notice that pressing/holding the ON key has various functions scattered through the program.
EDIT(2): Just so you don't have to figure it out: The floodfill uses a buffer the size of the screen to store points which haven't been looked at yet. It stores points which have been flooded, ignores points which were of the boundry color. Also, the screen is inverted conditionally to ease the actual routine's job. Pressing a key while the floodfill is executing will show this.
Last edited by CalcKing on Wed 13 Apr, 2005 7:41 pm, edited 1 time in total.
Thanks CalcKing, I'll take a more cursory look later.
edit: That is indeed an interesting use of the stack Now I just need to decipher your code and undo the excess stack usage, since my program actually respects the stack It seems that you have an off-by-one error somewhere when you pan left/right and rotate left/right; need to trace it though to figure it out.
Oh, as a head's up, my pen routine works exactly like CalcKing's pen
edit: That is indeed an interesting use of the stack Now I just need to decipher your code and undo the excess stack usage, since my program actually respects the stack It seems that you have an off-by-one error somewhere when you pan left/right and rotate left/right; need to trace it though to figure it out.
Oh, as a head's up, my pen routine works exactly like CalcKing's pen
"If SOURCE is outlawed, only outlaws will have SOURCE."
If you're talking about the fact that the full width is used, then I could fix that if you want... otherwise, I wasn't aware of any problems with the scrolling. My goal, again, was to use as much of the screen as one could store in a PicX variable. They do store the right column, at least last time I checked.
That is a very interesting result of the interaction of the two methods of scrolling... The pixel gets carried to the next row, then they all get set back. I'll try to give an ASCII diagram:
It's in a code box to make the format look better,
Code: Select all
ABCD -- "scroll - BCDZ -- "pan ---- ZBCD
ZYXW -- left" --- YXWA -- right" -- AYXW
EDIT: The thing I haven't figured out yet is why WINDOW+ZOOM+Right == Diagonal up+right...
1 year anniversary of laziness!
Well, tomorrow/today (Nov. 1st) is the 1 year anniversary! ... of last modifying (i.e. working on) my drawing program. I'm not exactly sure why I haven't been motivated enough to finish this, but I am willing to bet on my numerous distractions (e.g. homework, sidetracking on other projects, the usual...). Anyway, I have decided to post this for "testing" and feedback, and perhaps some motivation might come about I am really considering a recode, not that the source is cluttered (it's nicely commented, in fact), but because it's REALLY slow using plotLoc/bufferOnly and _ILine/et cetera for some of the drawing routines. Also, I have not yet included CalcKing's code, so those features are missing. Anyway, I welcome you to (finally) check it out and give me some feedback
http://www.geocities.com/kryptic_89/calcs/picide.html
http://www.geocities.com/kryptic_89/calcs/picide.html
"If SOURCE is outlawed, only outlaws will have SOURCE."
Yeah, I did get my initial interface idea from Sketchy, 'cause it was a cool App
But featurewise, what do you guys think? Is the speed for drawing ok, or should I ditch _ILine? What about the pen/erase/invert push-button-toggle-something functionality? And is that a good default cursor speed? Anything you guys want or need in the "drawing program to rule them all" (as dysfunction eloquently put it )?
edit: The size can actually be reduced by 768*2 bytes if I replace the title screen with something a bit more simplistic
But featurewise, what do you guys think? Is the speed for drawing ok, or should I ditch _ILine? What about the pen/erase/invert push-button-toggle-something functionality? And is that a good default cursor speed? Anything you guys want or need in the "drawing program to rule them all" (as dysfunction eloquently put it )?
edit: The size can actually be reduced by 768*2 bytes if I replace the title screen with something a bit more simplistic
"If SOURCE is outlawed, only outlaws will have SOURCE."