The drawing program to rule them all

Got a brilliant program idea? Let us know!

Moderator: MaxCoderz Staff

Gambit
Sir Posts-A-Lot
Posts: 252
Joined: Mon 21 Feb, 2005 5:34 am
Location: Laveen, Arizona

Post by Gambit »

I would be most interested in your source :); it looks like you did what I've been meaning to do for the past ... 5 MONTHS! :shock:
Fill Area
Flip Screen X and Y
Something is better than nothing :)
"If SOURCE is outlawed, only outlaws will have SOURCE."
CalcKing
Regular Member
Posts: 147
Joined: Sat 18 Dec, 2004 3:24 am
Contact:

Post by CalcKing »

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.

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
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:
  • -=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
Again, this is probably very strange code, the way I used the stack can be a bit confusing. :roll: :oops:

EDIT: Also notice that pressing/holding the ON key has various functions scattered through the program. :P
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.
User avatar
tr1p1ea
Maxcoderz Staff
Posts: 4141
Joined: Thu 16 Dec, 2004 10:06 pm
Location: I cant seem to get out of this cryogenic chamber!
Contact:

Post by tr1p1ea »

The way you used the stack is creative, not really necessary ... but creative :).

I have used this app a few times and it is quite cool :).
"My world is Black & White. But if I blink fast enough, I see it in Grayscale."
Image
Image
Gambit
Sir Posts-A-Lot
Posts: 252
Joined: Mon 21 Feb, 2005 5:34 am
Location: Laveen, Arizona

Post by Gambit »

Thanks CalcKing, I'll take a more cursory look later. :)

edit: That is indeed an interesting use of the stack :D Now I just need to decipher your code and undo the excess stack usage, since my program actually respects the stack :wink: 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 8)
"If SOURCE is outlawed, only outlaws will have SOURCE."
CalcKing
Regular Member
Posts: 147
Joined: Sat 18 Dec, 2004 3:24 am
Contact:

Post by CalcKing »

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.
Gambit
Sir Posts-A-Lot
Posts: 252
Joined: Mon 21 Feb, 2005 5:34 am
Location: Laveen, Arizona

Post by Gambit »

Try and get the axes on the screen, then pan left/scroll right, or pan right/scroll left. The left pixel column rotates for some reason. :?

Actually, my pen routine is a lot better than CalcKing's: it blinks! :P
"If SOURCE is outlawed, only outlaws will have SOURCE."
CalcKing
Regular Member
Posts: 147
Joined: Sat 18 Dec, 2004 3:24 am
Contact:

Post by CalcKing »

:lol: :lol: :lol:

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
Notice how the A and Z switched places. In a larger example, they would have moved along the left-most column. :wink: :roll: :P

EDIT: The thing I haven't figured out yet is why WINDOW+ZOOM+Right == Diagonal up+right... :puzzled:
Gambit
Sir Posts-A-Lot
Posts: 252
Joined: Mon 21 Feb, 2005 5:34 am
Location: Laveen, Arizona

1 year anniversary of laziness!

Post by Gambit »

Well, tomorrow/today (Nov. 1st) is the 1 year anniversary! :D ... of last modifying (i.e. working on) my drawing program. :x :roll: 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
"If SOURCE is outlawed, only outlaws will have SOURCE."
User avatar
kalan_vod
Calc King
Posts: 2932
Joined: Sat 18 Dec, 2004 6:46 am
Contact:

Post by kalan_vod »

I like it, reminds me of scetchy but seems smaller as of now :D.
Gambit
Sir Posts-A-Lot
Posts: 252
Joined: Mon 21 Feb, 2005 5:34 am
Location: Laveen, Arizona

Post by Gambit »

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 :P)?

edit: The size can actually be reduced by 768*2 bytes if I replace the title screen with something a bit more simplistic :P
"If SOURCE is outlawed, only outlaws will have SOURCE."
Post Reply