### Author Topic: Pixel on/off, drawing lines  (Read 3919 times)

0 Members and 1 Guest are viewing this topic.

#### aeTIos

• Nonbinary computing specialist
• LV12 Extreme Poster (Next: 5000)
• Posts: 3913
• Rating: +184/-32
##### Pixel on/off, drawing lines
« on: March 24, 2011, 04:17:05 am »
Hi,

How do you set a pixel on the screen on/ off?
How do you draw a line ?

Thanks!
I'm not a nerd but I pretend:

#### ZippyDee

• Posts: 729
• Rating: +83/-8
• Why not zoidberg?
##### Re: Pixel on/off, drawing lines
« Reply #1 on: March 24, 2011, 05:06:16 am »
I'm assuming you mean without using the built in ROM calls? Manipulating pixels is fairly straightforward. Drawing lines, however, is not. In order to draw lines without the use of b_calls you'll have to write an algorithm in assembly to do that yourself. I'd suggest Bresenham's line algorithm for that. I'm fairly new to ASM myself, so I don't think I could easily do or explain how to do that. Pixels, on the other hand, I can do.

Here's an explanation for manipulating pixels for the graph buffer (not directly plotting to the LCD):

Because of the nature of monochrome graphics, instead of representing each pixel with one or more bytes, each byte represents 8 pixels: one pixel for each bit. So in order to manipulate a specific pixel, you have to first find two things: The byte that contains the pixel, and which bit in that byte represents the pixel.

Getting the pixel:
Code: [Select]
GetPixel:    ; Inputs:    ;   A = x-coordinate, L = y-coordinate    ; Outputs:    ;   A = a bitmask for the pixel, HL = the address of the byte containing the pixel    ld h, 0    ld d, h    ld e, l    add hl, hl    ; the graph screen is arranged as an array of 12 x 64 bytes (12 bytes per row, 64 rows)    add hl, de   ; so in order to find the correct byte we first multiply the y coordinate by 12...    add hl, hl    add hl, hl    ld e, a    ; ...then add the x-coordinate/8 (because there are 8 pixels per byte)    srl e    srl e    srl e    add hl, de    ld de, PlotSScreen    add hl, de    ; now hl contains the address of the byte     and 7    ; this is the tricky part: finding the bit. Because there are 8 bits in each byte, we can do x-coordinate modulo 8    ld b, a    ; and that will return a number (0-7). That number tells us which bit to use (where "7" represents bit 0, and "0" represents bit 7)    ld a, $80 ; here we load the initial bitmask into A ret z ; if the "and 7" command returned 0, then the mask doesn't need to be rotated, so we can just return now._loop: rrca ; otherwise, rotate the bitmask B times (remember we loaded the result of "and 7" into B earlier) djnz _loop ret Turning a pixel on: Code: [Select]  call GetPixel or (hl) ; HL holds the byte, and A holds the mask, so we simply use or to turn on the masked pixel... ld (hl), a ;...then load it into the buffer Inverting a pixel: Code: [Select]  call GetPixel xor (hl) ; Same idea as before only using xor to invert ld (hl), a Turning a pixel off: Code: [Select]  call GetPixel cpl ; because AND clears any pixels that are already set, you have to invert the mask first and (hl) ld (hl), a NOTE: These only plot pixels in the graph buffer. You have to update the display before they will actually show up. Easiest way is just with B_CALL(_GrBufCpy), or you could write a custom routine, but that's a bit harder. Hope this helped! -Zippy Dee EDIT: Bresenham's line algorithm: http://en.wikipedia.org/wiki/Bresenham's_line_algorithm « Last Edit: March 24, 2011, 05:07:10 am by ZippyDee » There's something about Tuesday... Pushpins 'n' stuff... #### aeTIos • Nonbinary computing specialist • LV12 Extreme Poster (Next: 5000) • Posts: 3913 • Rating: +184/-32 ##### Re: Pixel on/off, drawing lines « Reply #2 on: March 24, 2011, 05:26:06 am » thanx! I'm not a nerd but I pretend: #### ZippyDee • LV8 Addict (Next: 1000) • Posts: 729 • Rating: +83/-8 • Why not zoidberg? ##### Re: Pixel on/off, drawing lines « Reply #3 on: March 24, 2011, 06:05:49 am » No problem! You can use the GetPixel routine for drawing vertical lines pretty easily, too. Vertical lines: Code: [Select]  ; Inputs: ; D is the x-coordinate, L is the starting y-coordinate and E is the ending y-coordinate ; make sure L is less than E, otherwise it'll go KABLOOIE!! or something... ld a, e sub l ; get the length of the line by subtracting L from E ret z ; if the length is zero, we don't need to draw it, so just return push af ; save the length of the line into the stack so we don't lose it ld a, d ; put the x-coordinate in A call GetPixel ; now A is the mask that we'll just use for all the rows and HL is the address of the starting byte for the line pop BC ; we pushed AF before, so now we pop to BC, so now B is the line length ld de, 12 ld c, a ; save the bitmask to C so we don't lose it_vloop: ld a, c ; restore the mask or (hl) ; turn the pixel on ld (hl), a add hl, de ; each row is 12 bytes, so to go to the next row we can just add 12 (which we stored in DE) to HL djnz _vloop ret You could potentially just loop GetPixel for each point in horizontal lines, too, but because the bytes group pixels horizontally, there are more efficient ways to do it. Unfortunately, I don't have a tested horizontal line routine, and I don't know that I'm good enough to really write an efficient one myself yet without doing tests first. Anyway, hope this helped even more! -Zippy Dee EDIT: I wrote out this routine just now, haven't tested it, but it should work. Maybe someone else can confirm. I'm not guaranteeing 100% efficiency, but it should be fine for almost all cases. Code: [Select]  ; Inputs: ; L =is the y-coordinate, D is the starting x-coordinate and E is the ending x-coordinate ; again, make sure D is less than E ld a, e ; get length, return if 0 sub d ret z srl a ; divide line length by 8 to find the number of bytes this line will span across (minus 1) srl a srl a push af ; save it for later ld h, 0 ; get the address of the byte containing the first pixel of the line ld b, h ; same code as in GetPixel, just using BC instead of DE because DE is currently occupied by our precious x-coordinates ld c, l add hl, hl add hl, bc add hl, hl add hl, hl ld c, d srl c srl c srl c add hl, bc ld bc, PlotSScreen add hl, bc ; now hl is the starting byte of the line call GetMask ;get the mask for the left end of the line pop bc ; length of the line goes into b ld c, a ; save the mask to c ld a, b or a ; if b is 0, mask the end of the line as well jr z, _lastbyte ld a, c_hloop: or (hl) ; apply the mask ld (hl), a inc hl ld a,$FF    ; after the first byte, the other bytes (except the last) will be masked with $FF so all pixels are turned on djnz _hloop_lastbyte: ld d, e dec d call GetMask ; get the mask for the right end of the line srl a ; because GetMask gives us the mask for the left end, we shift it one to the left and invert it to get the mask for the right end cpl and c ; get the similar bits between the previous mask and the current one (remember that if the length is less than 8, the masks for both the left and right ends have to be applied to the same byte) or (hl) ; now we apply the mask ld (hl), a ret ; and we're done! GetMask: ; this is also the same idea as getting the mask in GetPixel, only instead of rotating$80 we do a logical shift right on $FF to retrieve the mask for the ends of the line ld a, d and 7 ld b, a ld a,$FF    ret z_maskloop:    sra a    djnz _maskloop:    ret
« Last Edit: March 24, 2011, 06:57:25 am by ZippyDee »

Pushpins 'n' stuff...

#### Xeda112358

• they/them
• Moderator
• LV12 Extreme Poster (Next: 5000)
• Posts: 4699
• Rating: +718/-6
• Calc-u-lator, do doo doo do do do.
##### Re: Pixel on/off, drawing lines
« Reply #4 on: March 24, 2011, 10:30:55 am »
EDIT: As a note, the vertical and horizontal line commands draw across the whole screen
The easiest horizontal line I could come up  with...
Code: [Select]
;============================================DrawHoriz:;============================================;Input:;     l is the row to draw to;     a is the type of line to draw;        0 is a white line;        1 is a black line;        2 is an inverted line;============================================ ld h,0           ;2600        7 ld b,h           ;44          4 ld c,l           ;4D          4 add hl,bc        ;09         11 add hl,bc        ;09         11 add hl,hl        ;29         11 add hl,hl        ;29         11 ld bc,9340h      ;014093     10 add hl,bc        ;09         11 ld b,12          ;060C        7 or a             ;B7          4          Total: 91 jr z,DrawHoriz   ;2804       White: 12+318+91 dec a            ;3C          4 jr nz,DrawInvH   ;2006       Black: 4+4+7+7+318+91 dec a            ;3C          4DrawHoriz:        Total: 5 bytes, 318 cycles ld (hl),a        ;77          7          84 inc hl           ;23          6          72 djnz DrawHoriz   ;10FC       13*11+8    152 ret              ;C9         10          10DrawInv:          Total: 7 bytes, 450 cycles Invert: 4+7+12+450+91 ld a,(hl)        ;7E          7          84 cpl              ;2F          4          48 ld (hl),a        ;77          7          84 inc hl           ;23          6          72 djnz DrawInv     ;10FA       13*11+8    152 ret              ;C9         10          10;============================================;Stats:;============================================;Size: 33 bytes;Speed:;     White: 12+318+91             421 cycles;     Black: 4+4+7+7+318+91        431 cycles;     Inv:   4+7+12+450+91         564 cycles;============================================Here is a vertical line:
Code: [Select]
;============================================DrawVert:;============================================;Inputs:;     a is the column;     c is the method;        0 draws a white line;        1 draws a black line;        2 draws an inverted line;============================================    ld b,a               ;47    rrca \ rrca \ rrca   ;0F0F0F    and 1Fh              ;E60F    add 40h              ;C640    ld l,a               ;6F    ld h,93h             ;2693    ld a,b               ;78    and 7                ;E607    inc a                ;3C    ld b,a               ;47    ld a,1               ;3E01GetPixelMask:              rrca                 ;0F    djnz GetPixelMask    ;10FD    dec c                ;0D    jr nz,DrawVertW       ;200F     ld e,a               ;5F     ld bc,400Ch          ;010C40DrawVertBLoop:      ld a,e               ;7B      or (hl)              ;B6      ld (hl),a            ;77      ld a,b               ;78      ld b,0               ;0600      add hl,bc            ;09      ld b,a               ;47      djnz DrawVertBLoop   ;10F6    ret                    ;C9DrawVertW:    dec c                ;0D    jr z,DrawVertI       ;2001     cpl a                ;2FDrawVertI:     ld e,a               ;5F     ld bc,400Ch          ;010C40DrawVertILoop:      ld a,e               ;7B      xor (hl)             ;AE      ld (hl),a            ;77      ld a,b               ;78      ld b,0               ;0600      add hl,bc            ;09      ld b,a               ;47      djnz DrawVertBLoop   ;10F6    ret                    ;C9;============================================;Stats:;============================================;Size: 58 bytes;Speed: ... too lazy to calculate at the moment;     White: ;     Black: ;     Inv:   ;============================================Here is a pixel routine:
Code: [Select]
;============================================PlotPixel:       ;45 bytes;============================================;Inputs:;     b is the x coordinate;     c is the y coordinate;     e is the method;        0 draws a white line;        1 draws a black line;        2 draws an inverted line;============================================     ld a,b        ;78     ld b,0        ;0600     ld h,b        ;60     ld l,c        ;69     add hl,hl     ;29     add hl,bc     ;09     add hl,hl     ;29     add hl,hl     ;29     ld bc,9340h   ;014093     add hl,bc     ;09     ld b,a        ;47     rrca          ;0F     rrca          ;0F     rrca          ;0F     and 1Fh       ;E60F     ld c,a        ;4F     ld a,b        ;78     ld b,0        ;0600     add hl,bc     ;09     and 7         ;E607     ld b,a        ;47     inc b         ;04     ld a,1        ;3E01GetMask:      rrca          ;0F      djnz GetMask  ;10FD     dec e          ;1D     jr nz,DrawWPix ;2003      or (hl)       ;B6      ld (hl),a     ;77      ret           ;C9DrawWPix:     dec e          ;1D     jr z,DrawIPix  ;2801      cpl           ;2FDrawIPix:      xor (hl)      ;AE      ld (hl),a     ;77      ret           ;C9These can probably be optimised, but I just typed them up I am fairly sure the last can be optimised more.
« Last Edit: March 24, 2011, 10:51:04 am by Xeda112358 »

#### Deep Toaster

• So much to do, so much time, so little motivation
• LV13 Extreme Addict (Next: 9001)
• Posts: 8217
• Rating: +758/-15
##### Re: Pixel on/off, drawing lines
« Reply #5 on: March 24, 2011, 10:34:27 am »
[code] tags in [spoilers] :(
« Last Edit: March 24, 2011, 10:34:40 am by Deep Thought »

#### Xeda112358

• they/them
• Moderator
• LV12 Extreme Poster (Next: 5000)
• Posts: 4699
• Rating: +718/-6
• Calc-u-lator, do doo doo do do do.
##### Re: Pixel on/off, drawing lines
« Reply #6 on: March 24, 2011, 10:40:55 am »
Oh, sorry about that Sometime I need to see what happens in other browsers

#### Deep Toaster

• So much to do, so much time, so little motivation
• LV13 Extreme Addict (Next: 9001)
• Posts: 8217
• Rating: +758/-15
##### Re: Pixel on/off, drawing lines
« Reply #7 on: March 24, 2011, 10:47:16 am »
That's something the Chrome guys need to fix

#### aeTIos

• Nonbinary computing specialist
• LV12 Extreme Poster (Next: 5000)
• Posts: 3913
• Rating: +184/-32
##### Re: Pixel on/off, drawing lines
« Reply #8 on: March 24, 2011, 11:28:57 am »
huh, for horizontal lines, isnt there just the B_CALL _HorizCmd?

Oh wait, that requires OP1. I dont use OP1 atm lol.

Thanks for those neat routines!

I'm not a nerd but I pretend:

#### Xeda112358

• they/them
• Moderator
• LV12 Extreme Poster (Next: 5000)
• Posts: 4699
• Rating: +718/-6
• Calc-u-lator, do doo doo do do do.
##### Re: Pixel on/off, drawing lines
« Reply #9 on: March 24, 2011, 11:31:43 am »
Ah, usually using bcalls is slow, so I try to make routines that replace them. As an example, the horizontal commands can run over 10000 times in a second at 6MHz
EDIT: And  I stress "usually" because some cases aren't too bad. Also, the faster horizontal command can execute over 14 000 times in a second
« Last Edit: March 24, 2011, 11:33:37 am by Xeda112358 »

#### aeTIos

• Nonbinary computing specialist
• LV12 Extreme Poster (Next: 5000)
• Posts: 3913
• Rating: +184/-32
##### Re: Pixel on/off, drawing lines
« Reply #10 on: March 24, 2011, 11:39:53 am »
wow.
I'm not a nerd but I pretend:

#### Xeda112358

• they/them
• Moderator
• LV12 Extreme Poster (Next: 5000)
• Posts: 4699
• Rating: +718/-6
• Calc-u-lator, do doo doo do do do.
##### Re: Pixel on/off, drawing lines
« Reply #11 on: March 24, 2011, 11:42:48 am »
It is pretty impressive when you put it into perspective like that, right ? That is why sometimes the difference is negligible when using OS routines.

#### aeTIos

• Nonbinary computing specialist
• LV12 Extreme Poster (Next: 5000)
• Posts: 3913
• Rating: +184/-32
##### Re: Pixel on/off, drawing lines
« Reply #12 on: March 24, 2011, 11:44:20 am »
Yes, I cee. Nut if you use it a very big program it can just differ like a minute, I think
I'm not a nerd but I pretend:

#### thepenguin77

• z80 Assembly Master
• LV10 31337 u53r (Next: 2000)
• Posts: 1591
• Rating: +823/-5
• The game in my avatar is bit.ly/p0zPWu
##### Re: Pixel on/off, drawing lines
« Reply #13 on: March 25, 2011, 05:20:33 pm »
Nobody's given a diagonal line routine yet This one comes from Missile.

You need to define (increment) somewhere. I believe you also need a getpixel that takes de = xy for input and doesn't destroy anything.

Code: [Select]
;#;input: de = xy; hl = xyline: push hl push de ld b, 2fastLinePreLoop: ld a, d call xClipCheck ld d, a ld a, e call yClipCheck ld e, a ex de, hl djnz fastLinePreLoop or a sbc hl, de add hl, de jr nc, noSwitch ex de, hlnoSwitch: ld a, h sub d ld b, a ld a, l sub e ld c, 0 jp p, positivoz neg ld c, 1positivoz: cp b jr nc, yMajorxMajor: inc b ld h, a ld a, b call setUpForLoop bit 0, c jr z, notNeggaz inc hnotNeggaz: ld c, d xMajorLoop: push bc ld de, (increment) add hl, de push hl ld d, c ld e, h call getPixel ld a, c call middlePartOfLoop pop hl pop bc inc c djnz xMajorLoop pop de pop hl retyMajor: bit 0, c jr z, alreadySetUp ex de, hlalreadySetUp: inc a ld h, b ld b, a call setUpForLoop bit 0, c jr z, notNegga inc dnotNegga: ld c, h ld h, dyMajorLoop: push bc ld de, (increment) add hl, de push hl ld e, c ld d, h ld b, h call getPixel ld a, b call middlePartOfLoop pop hl pop bc inc c djnz yMajorLoop pop de pop hl ret middlePartOfLoop: ld c, 128 and %00000111 jr z, alreadyDone ld b, abyteLoop: srl c djnz byteLoopalreadyDone: ld a, c or (hl) ld (hl), a retsetUpForLoop: ld l, \$FF push de push bc call divHLbyA pop bc bit 0, c call nz, negHL ld (increment), hl pop hl ld d, h ld h, l ld l, 0 retyClipCheck: ;super efficient, no rets call isANeg cp 64 ret c ld a, 63xClipCheck: call isANeg cp 96 ret c ld a, 95isANeg: or a ret p xor a ret
zStart v1.3.013 9-20-2013
All of my utilities
TI-Connect Help
You can build a statue out of either 1'x1' blocks or 12'x12' blocks. The 1'x1' blocks will take a lot longer, but the final product is worth it.
-Runer112

#### ZippyDee

• Posts: 729
• Rating: +83/-8
• Why not zoidberg?
##### Re: Pixel on/off, drawing lines
« Reply #14 on: March 25, 2011, 05:38:12 pm »
Is that bresenham's?

Also, can someone who really knows what they're talking about confirm that my horizontal line routine is actually correct?
« Last Edit: March 25, 2011, 05:38:49 pm by ZippyDee »