Omnimaga

Calculator Community => TI Calculators => ASM => Topic started by: ZippyDee on March 20, 2011, 11:19:52 pm

Title: Bezier curves HELP!!
Post by: ZippyDee on March 20, 2011, 11:19:52 pm
Hi, I'm quite  new to ASM, so I probably made a bunch of mistakes.

I'm trying to write a program that draws a Bezier curve based on given control points. However......it doesn't seem to be working. I think it's an issue with my math for calculating the next iteration of control points, but I've looked it over again and again and I can't figure out what's wrong.  :banghead:

Here's the code, complete with a surplus of comments (probably more than I really need, but I just wanted to show my though processes).

//EDIT: Here's an explanation for constructing Bezier curves. Hopefully it'll help :)
http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Constructing_B.C3.A9zier_curves (http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Constructing_B.C3.A9zier_curves)


Code: [Select]
.nolist
#include "ti83plus.inc"
#define    ProgStart    $9D95
.list
.org    $9D95 - 2
    .db    t2ByteTok, tAsmCmp

b_call(_GrBufClr) ;clear stuff...
b_call(_ClrLCDFull)

ld a, 255
ld (_time), a ;set _time to 255 (when used in calculation it ends up acting as a lower part of a fixed point number)
ld a, (_len) ;_len is always 4 right now. That'll change once I get this thing working.
ld (_level), a
call LoadVals ;load the _initx and _inity values into _px and _py
_tloop:
call Bezier ;calculate and plot the point on the curve at _time
call LoadVals ;reload the _initx/y values
ld hl, _time
dec (hl) ;dec _time
xor a
cp (hl)
jr nz, _tloop ;loop until _time is zero

call Plot ;plot the first point (shouldn't be necessary, but just in case)

ld hl, _px ;load points at _px+(_len) and _py+(_len) into _px and _py
ld bc, (_len)
dec bc ;_len is the total length, so subtract one to get the last one
add hl, bc ;set hl to address of _px+(_len)
ld de, _px
ldi

inc bc ;ldi decrements bc, so add 1 to restore it
add hl, bc
ld de, _py
ldi

call Plot
b_call(_GrBufCpy)
ret


LoadVals:
ld hl, _initx
ld de, _px
ld bc, 8
ldir
ret


Bezier:
ld a, 0
ld (_n), a ;reset _n
ld hl, _level
dec (hl) ;go to next (or first) level iteration

ld a, (hl)
cp 0
jr nz, bez

call Plot ;if the level is zero, draw the point at _px,_py to the graph buffer
b_call(_GrBufCpy) ;display for testing purposes
jr bez_ret ;end the routine

bez:
ld hl, (_n) ;for each point p[_n] where _n=0 to _n=_level-1
ld h, 0 ;_n is one byte, so zero out h
push hl ;save _n
ld de, _px ;we want to calculate the _nth byte starting at _px
;Div_pt has add hl,de in it.
call Div_pt
ld (hl), a ;save the new x coordinate to _px[_n]

pop hl ;restore _n
ld de, _py ;now we want the _nth byte starting at _py
call Div_pt
ld (hl), a ;save the new y coordinate to _py[_n]

ld hl, _n
ld a, (_level)
inc (hl) ;_n=_n+1
cp (hl)
jr nc, bez ;loop until _n>=_level-1

call Bezier ;call Bezier again to calculate the next level iteration

bez_ret:
ld hl, _level
inc (hl) ;reset _level to the previous level iteration before returning
ret


Div_pt:
;input
; de = start address of point array
; hl = value at _n
;output
; a = p[_n]+(p[_n+1]-p[_n])*(_time/256)
; hl = address of p[_n]
;note that p[ ] is either _px[ ] or _py[ ] depending on input de value

add hl, de ;find the address of the desired byte
push hl
pop de
inc de ;de = hl+1
ld a, (de)
sub (hl) ;subtract p[_n] (at hl) from p[_n+1] (at de)
;a is now the difference of the two points

push hl ;save location of p[_n]
ld e, 0
jr nc, _pskip
ld e, 1 ;if (de)-(hl) is negative, e is 1
neg ;make a positive
_pskip:
;##################################################################
;##################################################################

;This is the part that I guess isn't working

;Basically, I'm using _time as a percentage (where 256 is 100%)
;The point at _time percent of the line between p[_n] and p[_n+1] is calculated here
;    and stored in a (later stored in p[_n] back in the main Bezier routine)

;I'm calculating this:
;   p[_n]+(p[_n+1]-p[_n])*(_time/256)

ld h, a ;make hl fixed point with value a
ld l, 0
ld a, (_time)
ld d, a ;multiply by _time
push de ;save e, which holds the sign
call HL_Times_D
;because HL is 2 bytes and D is one byte, this SHOULD be the same
;  as multiplying by d as if it was the decimal part of a fixed point number

pop de ;restore e
ld a, e
cp 0 ;check for negative
ld a, h ;in case of negative, get the value to invert
jr z, _nskip
neg ;if a was negative before, make it negative again
_nskip:
pop hl
add a,(hl) ;add the original p[_n] value
ret
;##################################################################
;##################################################################

Plot:
ld a, (_py) ;get the y coordinate into l
ld l, a
or a
ret m ;ret if negative
cp 64
ret nc ;ret if y>=64
ld a, (_px) ;get x
or a
ret m ;ret if negative
cp 96
ret nc ;ret if x>=96
call GetPixel ;turn on pixel (x,y)
or (hl)
ld (hl), a
ret


GetPixel: ;this came from the "Learn TI-83/84+ ASM in 28 days" or whatever guide
;a = x coordinate
;l = y coordinate
ld h, 0
ld d, h
ld e, l
add hl, hl
add hl, de
add hl, hl
add hl, hl
ld e, a
srl e
srl e
srl e
add hl, de
ld de, PlotSScreen
add hl, de
and 7
ld b,a
ld a, $80
ret z
__gloop:
rrca
djnz __gloop
ret


HL_Times_D: ;this came from the "Learn TI-83/84+ ASM in 28 days" or whatever guide
;in the guide it was DE_Times_A, but I was already using HL and D for division
;  so I thought it was a good idea to just keep those values
ld a, d
ld de, 0
ex de, hl
ld b, 8
__mloop:
rrca
jr nc, __mskip
add hl, de
__mskip:
sla e
rl d
djnz __mloop
ret


Div_HL_D: ;this came from the "Learn TI-83/84+ ASM in 28 days" or whatever guide
xor a
ld b, 16
__dloop:
add hl, hl
rla
jr c, __overflow
cp d
jr c, __dskip
__overflow:
sub d
inc l
__dskip:
djnz __dloop
ret


_time:
.db 0
_level:
.db 0 ;control point iteration level
_n:
.db 0 ;control point to calculate at any given time
_len:
.dw 4 ;number of control points for the curve
_initx:
.db 4, 7, 13, 20 ;control point x values
_inity:
.db 6, 23, 19, 2 ;control point y values
_px:
.db 0, 0, 0, 0 ;x values for calculations
_py:
.db 0, 0, 0, 0 ;y values for calculations
.end
.end

If anyone could help me out that would be wonderful!

Thanks!
-Zippy Dee
Title: Re: Bezier curves HELP!!
Post by: ztrumpet on March 21, 2011, 05:19:37 pm
I doubt if this will help, but Michael_Lee made a routine to do this in Axe: http://ourl.ca/4129/186296

Sadly, I don't understand Asm well and can't help you, but hopefully someone else will stumble over this thread who can help.  Good luck! :)
Title: Re: Bezier curves HELP!!
Post by: Builderboy on March 21, 2011, 05:27:17 pm
Maybe it would help by instead of going pixel by pixel, do what Michale_Lee did and just calculate 8 or so points on the curve and connect them with straight lines.  Unfortunately I too can only provide conceptual help, as I am not an asm expert either D:
Title: Re: Bezier curves HELP!!
Post by: Michael_Lee on March 21, 2011, 07:37:50 pm
Blasphemy!  People spelled my name incorrectly, twice!

I don't know any asm at all, so I'm of even less help, but I can point you to a webpage I found which provided the algorithm I adapted: http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm (http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm)
Title: Re: Bezier curves HELP!!
Post by: ztrumpet on March 21, 2011, 07:40:06 pm
Blasphemy!  People spelled my name incorrectly, twice!
I'm very sorry.  :-X  This is why I should check things like this before posting.  <_<
Title: Re: Bezier curves HELP!!
Post by: Builderboy on March 21, 2011, 07:42:07 pm
I spelt it wrong because I was copying it from ztrumpet :P

* Hides *
Title: Re: Bezier curves HELP!!
Post by: Michael_Lee on March 21, 2011, 07:44:07 pm
It's fine - don't worry about it.
I just like to say the word 'blasphamy'. :)

...

Blasphamy!
Title: Re: Bezier curves HELP!!
Post by: thepenguin77 on March 21, 2011, 09:38:59 pm
First off, I love how this is structured, nested loops are so cool and clever. But it's amazing that such a small mistake can cause the entire program to fail.

You had:
Code: [Select]
ld h, a
ld l, 0

You wanted:
Code: [Select]
ld h, 0
ld l, a

Down in your problem area. By putting time in l, then reading it from h, you are essentially dividing it by 256. I attached a file with some edits I made to it, it works fine with just that little change, but these are just some things to help you. For instance, I think it just looks better to render from left to right, but that might just be me.

The lines don't come out that pretty because you are getting some serious rounding issues (11 rounds per pixel), so I would suggest making all of your number .256 decimal, but of course that requires a complete rewrite. I'll see if I can give you an example so you can see what it would look like.

And lastly, you can get some serious speed improvements by using a custom GrBufCpy, or even better yet, only plot the current byte in the LCD driver, but that's a bit advanced.
Title: Re: Bezier curves HELP!!
Post by: thepenguin77 on March 22, 2011, 08:53:54 pm
I was bored, so here is that demo I talked about. It uses 256 point decimal, which is great for physics applications.

It is also commented for clarity.
Title: Re: Bezier curves HELP!!
Post by: ZippyDee on March 24, 2011, 01:20:45 am
I swear I tried that. I tried putting time in H and L and I tried both multiplying and dividing (which is why I had both Div_HL_D and HL_Times_D there). Oh well, thank you so much! And thanks for all the comments and for that other example (which is obviously 10,000,000,000 times better than mine, and way over my head)!

Can you explain what you mean about making all the numbers .256 decimal? You mean like fixed-point numbers? I was going to try to make it fixed-point, but all the scaling that's involved for the multiplication confused me, so I gave up. I also was going to try to make it write to the LCD, but I figured it's probably best to get one that just WORKS before trying to get too fancy (Well, what an ASM noob like me considers fancy).

Thanks for all your help! I'm really trying to learn to navigate ASM, and this alone has been very enlightening. It's always the small things that get you. :P
Title: Re: Bezier curves HELP!!
Post by: ZippyDee on March 24, 2011, 07:11:30 am
I don't know any asm at all, so I'm of even less help, but I can point you to a webpage I found which provided the algorithm I adapted: http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm (http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm)
Thanks! That's actually a fairly good explanation on that page. That's only for cubic beziers though, isn't it? Though you don't often need more than a cubic bezier...

Also, now that you've done a bezier routine in axe (which looks fantastic and is very speed-efficient), you should write a b-spline routine :D

Edit: oops, sorry for the double post :\
Title: Re: Bezier curves HELP!!
Post by: thepenguin77 on March 25, 2011, 05:13:17 pm
Sorry for the over your head stuff, lately I've been tending to write pretty cryptic code for optimizations. Like using a loop to do x then y, but that's just easier for me I guess.

When I say .256 decimal, I mean fixed point decimal, but in a very specific way. First you take your typical 1 byte value, and place it in the high byte of a two byte number. The lower byte of that two byte is now its decimal place. So just treat it like a two byte number, and when the time comes to see what the value is, only read the upper byte.

As for updating the LCD, that example right there is a clean as it gets (I love DWAIT.) Just make sure that you grab the byte from the buffer, or else you will overwrite the old bits with white.
Title: Re: Bezier curves HELP!!
Post by: ZippyDee on March 25, 2011, 05:36:59 pm
Isn't the LCD done with columns x rows instead of rows x columns though? I thought I saw that somewhere...
Title: Re: Bezier curves HELP!!
Post by: thepenguin77 on March 25, 2011, 10:51:44 pm
Well, that's technically a yes. But in all reality, it doesn't matter at all. The only time it matters is when you are sending commands 4-7 which set the way the driver moves after each write (up, down, left, right). But at least on wikiTI (http://wikiti.brandonw.net/index.php?title=83Plus:Ports:10) it says both the x/y and the vertical/horizontal, so you don't have to worry about it.

Also, it's pretty easy to remember that the columns start at $20 and the rows start at $80. Those are the two numbers you'll need if you write a graphBufferCopy routine.
Title: Re: Bezier curves HELP!!
Post by: ZippyDee on March 26, 2011, 05:01:07 am
Also, it's pretty easy to remember that the columns start at $20 and the rows start at $80.
What do you mean by that?
Title: Re: Bezier curves HELP!!
Post by: thepenguin77 on March 26, 2011, 09:49:05 pm
What I mean is that the LCD commands for which column are $20-$2B and row are $80-$BF.
Title: Re: Bezier curves HELP!!
Post by: ZippyDee on March 28, 2011, 01:35:28 am
Ohhhh for setting the column/row. Okay. That makes more sense.