Welcome, Guest. Please login or register.

Author Topic: I want an asm-float-routine  (Read 3417 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline GreatLorTopic starter

  • Jr. Member
  • **
  • Join Date: Apr 2004
  • Posts: 72
    • Show only replies by GreatLor
I want an asm-float-routine
« on: June 05, 2004, 03:32:09 PM »
Thats right, I have rewritten my amos-vector routine in assembler, and tried things like storing the 3d coordinates (x,y,z) shifted - say - 8 positions left, I then multiply these multiplied coordinates with sinus values (shifted 14 bytes to left), then before storing the coords again I shift them 14 positions to the right and store them, then in the 2d_projecting routine I divide these (still left-shifted 8 postions) with - say - projected_x = dist*x/(dist+z), (converted to assembler code offcourse) and store them in 2d coordinate tables, and finally before I send these to my drawPixel routine I left-shift them 8 positions and add the relevant x/y offsets (150 & 120).

Now just like I thought every 2d AND 3d coords become 0. so does anyone have any float-routine in some sort ?, I dont really have the time/energy to think of one such, would be REALLY boring to see the code I've written to go to HELL !  :-D
 

Offline Hattig

  • Hero Member
  • *****
  • Join Date: Feb 2002
  • Posts: 901
    • Show only replies by Hattig
Re: I want an asm-float-routine
« Reply #1 on: June 05, 2004, 04:48:02 PM »
Why not use hardware floating point if you want floating point?

Also, you should always translate an object from an unchanging definition, otherwise numerical error will eventually turn a cube into something "notacube", and so on. If you are updating vertice information, you might as well do a single matrix transformation from the original vertices as opposed to the previously generated vertices.

I suppose you could do integer "floating point" though. Have a 360 entry (for 1 degree accuracy) Sine table holding values between -2^20 and 2^20 (-1 and 1) and your vertice values between -2^11 and 2^11 then multiply and shift the result right by 20 places to get the translated position.
 

Offline KapitanKlystron

  • Full Member
  • ***
  • Join Date: Sep 2002
  • Posts: 132
    • Show only replies by KapitanKlystron
Re: I want an asm-float-routine
« Reply #2 on: June 05, 2004, 06:01:24 PM »
Don't forget to carry the "nought"

(Every thing I know about math I learned from Jethro on the Beverly Hillbillies) :-D  :-)  :lol:
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
Re: I want an asm-float-routine
« Reply #3 on: June 05, 2004, 09:00:22 PM »
@GreatLor

Woah!  Take it easy with the shifting!  I take it that you're doing all the shifting to try to optimize your 2D/3D routine?  Lets see if we can figure out why things are going wrong.

So, we have a 2D point (or vector if you prefer) at <10,10>.  We want to rotate it clockwise 30 degrees (i.e. about the Z axis).  To do this we need to multiply the x component by cos 30 and the y component by sin 30:

x' = x * cos(θ) - y * sin(θ)
y' = y * cos(θ) + x * sin(θ)

Now, the real problem here is that most Amigas don't do floating point math very quickly and sin() and cos() always return a value less than 1 so when converted to an integer they are always 0, hence x and y are always 0!  This is not good!  So how do we get around that?

One way is to use floating point math, but this is both difficult in assembly and slow in practice.  Another way, and what I think you were trying to do, is to use fixed point math.  This method scales all values by some constant so that the sin() and cos() values are not rounded off to zero.  The formulas can be rewritten as:

x' = ((x * cos(θ) * SCALE) - (y * sin(θ) * SCALE)) / SCALE
y' = ((y * cos(θ) * SCALE) + (x * sin(θ) * SCALE)) / SCALE

Using a shift left is a quick way to scale a number by a power of 2.  Shifting 7 bits scales it by 128 and is the same as multiplying the number by 128.  If we choose a good scale factor and scale all of our operations by it then things will come out fine.

So lets look at our vector and try to write a routine in AMOS to rotate it 30 degrees:
Code: [Select]

Degree

Rem never change the originals!
X = 10
Y = 10

Rem Our scale factor
SCALE = 128

Rem Rotate THETA degrees
THETA = 30

Rem Scale the sin() and cos() values
_SIN = Sin(THETA) * SCALE
_COS = Cos(THETA) * SCALE

Rem Compute the new (scaled) values
_X = X * _COS - Y * _SIN
_Y = Y * _COS + X * _SIN

Rem Unscale the coordinates
_X = _X / SCALE
_Y = _Y / SCALE

Rem Here is the new point
Plot _X, _Y

Now, in assembly:
Code: [Select]

           move.l X,d0        X-coord in d0
           move.l Y,d1        Y-coord in d1
           muls.w COS30,d0    X * cos(30)
           muls.w SIN30,d1    Y * sin(30)
           sub.l d1,d0        (X * cos(30)) - (Y * sin(30))
           lsr.l #7,d0        Unscale X
           move.l d0,_X       New x-coord
           move.l X,d0        X-coord in d0
           move.l Y,d1        Y-coord in d1
           muls.w COS30,d1    Y * cos(30)
           muls.w SIN30,d0    X * sin(30)
           add.l d0,d1        (Y * cos(30)) + (X * sin(30))
           lsr.l #7,d1        Unscale Y
           move.l d1,_Y       New y-coord
           rts

_X         ds.l 1    Storage for x-coord
_Y         ds.l 1    Storage for y-coord

X          dc.l 10   Initial x-coord
Y          dc.l 10   Initial y-coord
SIN30      dc.w 64  sin(30)*128
COS30      dc.w 110  cos(30)*128

Notice that since we've scaled the sine and cosine values, we don't need to scale the x and y coordinates.  Doing so will cause problems.  Also, everything must use the same scale factor.  Trying to shift the sines and cosines by 14 bits and the coordinates by 8 bits will not work!

Anyway, I hope this helps.  Let me know how it works for you.
Sidewinder
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
Re: I want an asm-float-routine
« Reply #4 on: June 06, 2004, 07:38:39 PM »
@GreatLor

Also, if you really want to use float routines in assembly the best way to do this is to use the mathffp.library and the mathtrans.library.

The mathffp.library contains the routines to use numbers encoded in Motorola's Fast Floating Point format. These are the basic operations like add, subtract, multiply, divide, as well as functions to compare FFP numbers and convert them into integers, etc.

The mathtrans.library contains more complex operations like trig functions (Sine, Cosine, Tangent) as well as square roots and conversion routines to and from the IEEE format for use with FPUs.

C has a link library called mathlink_lib.lib that contains functions to convert a string into an FFP value, but assembly offers no interface to these functions.  This means that you'll have to convert the numbers into FFP format yourself.  To do that you need to understand how FFP works.

A float can be represented as something like:

-6.7344e-3 or -6.7344 x E^-3

Here the first character is the sign.  In this case it is negative.  The sign is followed by the mantissa (6.7344).  The mantissa is followed by the exponent, which is the number after the "E" or "e".  In this case the exponent is negative.  The exponent tells us how far, and which direction to move the decimal point to arrive at the real value.  Negative exponents mean move left (smaller numbers), positive exponents mean move right (larger numbers).

The above number is equal to the value -0.0067344.

The FFP format is a 32 bits arranged as:

MMMMMMMM MMMMMMMM MMMMMMMM SEEEEEEE

Bits 0 through 6 represent the exponent in excess-64 notation.  Simply take this value and subtract 64 to get the real exponent.  This means that a value of 0 represents an exponent of -64 and a value of 127 represents an exponent of +63.

If our float value is in d0 then
Code: [Select]

    move.b d0,d1    move the lowest byte into d1
    andi.b #$7f,d1  AND d1 with $7f for only the exponent
    sub.b #64,d1    d1.b now holds the exponent value

will place the exponent in d1.

Bit 7 is the sign of the number.  0 is positive and 1 is negative.

Using
Code: [Select]

    btst.b #7,d0    Test if the value is positive

we can test the sign of the value and use the bne or beq instruction to take action if it is positve or negative.

Finally bits 8 through 31 represent the mantissa.  The mantissa is always normalized, which means that bit 31 is always set (unless representing a value of zero).  This allows us to get as much data as possible into the 24 bits of the mantissa because there are no leading zeros.

Using the code
Code: [Select]

    move.l d0,d2   copy ffp into d2
    lsr.l #8,d2    shift right 8 bits

we can extract the mantissa.

So, lets say we want to try to encode the number -6.7344e-3 into FFP format.

First of all, we know the number is negative, so the sign bit (bit 7) will be set:

00000000 00000000 00000000 10000000

we also know that the exponent is -3.  We convert to excess-64 notation by adding 64 so the exponent is 61.  In binary 61 is 111101 so we plug that into the first byte:

00000000 00000000 00000000 10111101

The mantissa is 6.7344.  Ignore the decimal point for now and we get 67,344 which is 10000011100010000.  We plug this in and get:

00000001 00000111 00010000 10111101

But the mantissa must be normalized (i.e. have a 1 in bit 31).  So we shift the 24 bits of the mantissa to the left 7 bits:

10000011 10001000 00000000 10111101

This is -6.7344e-3 encoded in FFP format.  To load it into a register for use with the mathffp.library functions we can convert it into hex:

$838800bd

and use a move.l instruction:
Code: [Select]

    move.l #$838800bd,d0

One more thing.  The number zero is a special case in FFP.  It is represented by a long word of all zeros:
Code: [Select]

    clr.l d0

And that's pretty much it.  Let me know if you have any questions.




Sidewinder
 

Offline GreatLorTopic starter

  • Jr. Member
  • **
  • Join Date: Apr 2004
  • Posts: 72
    • Show only replies by GreatLor
Re: I want an asm-float-routine
« Reply #5 on: June 07, 2004, 04:10:32 PM »
Hi folks !  :-) , while reading your posts (not finished reading) I wanted to say that the error was due to the fact that I called my sinus function and the returned values I placed in memory locations labeled 'sin' and 'cos', and every time I wanted to multiply these with the 3d coordinated I DIRECTLY did "muls cos,d0", yes, you see the wrong in this, man it took HOURS to find the bug, anyway with some modifications to the code it runs nice now except for one thing, the 2d projecting routine which obviously doesnt working properly (the coordinates arent perspectivized at all), so I'll be busy some more hours with that.

oh and no, I'm not using matrices of any kind, I havent found any page/literature that learns this out step by step for ppl that havent EVER worked with matrices, the stupid pages (the authors that is) seem to think that someone like me is used to them (matrices), they forget that you read their texts to learn something you dont know yet, anyway if someone knows of any page who describes matrices with some kind of a philosopic point of view please link me there.


*EDIT*

Really appreciate your explenations Sidewinder.

Hattig, you dont happen to have time to write a tutorial about matrices ?
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
Re: I want an asm-float-routine
« Reply #6 on: June 09, 2004, 03:12:03 AM »
@GreatLor

Since Hattig hasn't jumped at the chance to explain matrices I think I'll give it a try.

A matrix is a concept for linear algebra.  It is basically an array of numbers enclosed by square brackets.  It looks something like (please image the "|" characters are connected):
Code: [Select]

[font=Courier]
 
| 1  6  34  2  |
| 23 45 10  87 |
| 12 37 9   56 |
| 0  4  75  42 |
 
[/font]

A matrix is an efficent way to represent a set of linear equations:
Code: [Select]

[font=Courier]
 
  x - 2y +  z =  0
      2y - 8z =  8
-4x + 5y + 9z = -9
 
[/font]

can be represented as:
Code: [Select]

[font=Courier]
 
| 1 -2  1  0 |
| 0  2 -8  8 |
|-4  5  9 -9 |
 
[/font]

When you think about this for a little while it becomes clear that a vector (2D or 3D point) can be represented as a set of linear equations and, thus, also as a matrix:
Code: [Select]

[font=Courier]
 
<10, 5, 7>
 
[/font]

can become
Code: [Select]

[font=Courier]
 
1x + 0y + 0z = 10      x = 10
0x + 1y + 0x = 5   ==  y = 5
0x + 0y + 1z = 7       x = 7
 
[/font]

or simply the matrix
Code: [Select]

[font=Courier]
 
| 10 |
|  5 |
|  7 |
 
[/font]

Matrices can be added and subtracted from eachother by adding or subtracting the value in each position of one matrix with the value in the same position in the other matrix.
Code: [Select]

[font=Courier]
 
| 1  0  2 |     | 3  5  -1 |     | 4  5  1 |
| 3 -1  4 |  +  | 2  7   0 |  =  | 5  6  4 |
|-2  8  7 |     | 4 -8  11 |     | 2  0 18 |
 
| 1  0  2 |     | 3  5  -1 |     |-2 -5  3 |
| 3 -1  4 |  -  | 2  7   0 |  =  | 1 -8  4 |
|-2  8  7 |     | 4 -8  11 |     |-6 16 -4 |
 
[/font]

They can be multiplied too, but it's a bit more tricky.  To do this we multiply each row of the first matrix by each column of the other matrix, element by element.  Add the resulting numbers and then we place the result in the location of of the row number and column number that we used.  Here's a small example:
Code: [Select]

[font=Courier]
 
| 2  5 |   | 4  6 |
| 3  4 | * | 1  2 |
 
[/font]

Take the first row of the first matrix and multiply each number by the first column of the second matrix, sum the result:
Code: [Select]

[font=Courier]
 
r1 * c1 = (2 * 4) + (5 * 1) = 13
 
[/font]

repeat for the other row/column combinations:
Code: [Select]

[font=Courier]
 
r2 * c1 = (3 * 4) + (4 * 1) = 16
r1 * c2 = (2 * 6) + (5 * 2) = 22
r2 * c2 = (3 * 6) + (4 * 2) = 26
 
[/font]

Then we take these results and place them into a matrix using their rows and columns as coordinates:
Code: [Select]

[font=Courier]
 
     c1  c2
r1 | 13  22 |
r2 | 16  25 |
 
[/font]

so
Code: [Select]

[font=Courier]
 
| 2  5 |   | 4  6 |   | 13  22 |
| 3  4 | * | 1  2 | = | 16  25 |
 
[/font]

in 3D it's the same thing:
Code: [Select]

[font=Courier]
 
| 1  0  2 |     | 3  5  -1 |
| 3 -1  4 |  *  | 2  7   0 |  =  ?
|-2  8  7 |     | 4 -8  11 |
 
(1 * 3) + (0 * 2) + (2 * 4) = 11
(3 * 3) + (-1 * 2) + (4 * 4) = 23
(-2 * 3) + (8 * 2) + (7 * 4) = 38
 
(1 * 5) + (0 * 7) + (2 * -8) = -11
(3 * 5) + (-1 * 7) + (4 * -8) = -16
(-2 * 5) + (8 * 7) + (7 * -8) = -10
 
(1 * -1) + (0 * 0) + (2 * 11) = 21
(3 * -1) + (-1 * 0) + (4 * 11) = 41
(-2 * -1) + (8 * 0) + (7 * 11) = 79
 
| 1  0  2 |     | 3  5  -1 |     | 11 -11 21 |
| 3 -1  4 |  *  | 2  7   0 |  =  | 23 -16 41 |
|-2  8  7 |     | 4 -8  11 |     | 38 -10 79 |
 
[/font]

I hope I did all that math correctly.  Anyway, this method can easily be adapted using two nested For loops to cycle through each row and multiply it by each column.

Ok, so that's matrix theory.  In 3D graphics we use 4 x 4 matrices.  This extra dimension is necessary to make the operations work out properly.  But because the matrices are 4 x 4, the vectors also have to be 4 numbers or [x y z 1].

So our point represented as a 3D vector looks like:
Code: [Select]

[font=Courier]
 
[10 5 7 1]
 
[/font]

Now, there is a special matrix called the identity matrix.  It is simply a matrix with a diagonal of 1's:
Code: [Select]

[font=Courier]
 
| 1  0  0  0 |
| 0  1  0  0 |
| 0  0  1  0 |
| 0  0  0  1 |
 
[/font]

This matrix is useful because if you multiply any vector by the identity matrix you get the vector back again.  This may not seem too important now, but it is really quite useful because all other transformation matrices use it as a starting point.

To translate (move) a vector to a new position in 3D space we use the translation matrix:
Code: [Select]

[font=Courier]
 
| 1  0  0  0 |
| 0  1  0  0 |
| 0  0  1  0 |
| dx dy dz 1 |
 
[/font]

If we multiply our vector by this matrix we get the new position of the vector!  Lets try to move our point 2 units right, 7 units down, and 10 units back:
Code: [Select]

[font=Courier]
 
             | 1  0  0  0 |
[10 5 7 1] * | 0  1  0  0 | = [12 -2 17 1]
             | 0  0  1  0 |
             | 2 -7 10  1 |
 
[/font]

It worked!

Now the same thing works for other operations like scaling and rotating.  Just multiply the vector by the correct matrix.

The scaling matrix is:
Code: [Select]

[font=Courier]
 
| sx 0  0  0 |
| 0  sy 0  0 |
| 0  0  sz 0 |
| 0  0  0  1 |
 
[/font]

If each dimension is to be scaled the same amount then this can become:
Code: [Select]

[font=Courier]
 
| s  0  0  0 |
| 0  s  0  0 |
| 0  0  s  0 |
| 0  0  0  1 |
 
[/font]

Where s is the scale factor.

Rotations can be done with matrices also.  To rotate about the X-axis use the matrix:
Code: [Select]

[font=Courier]
 
| 1    0       0     0 |
| 0  cos(T)  sin(T)  0 |
| 0 -sin(T)  cos(T)  0 |
| 0    0       0     1 |
 
[/font]

About the Y-axis it is:
Code: [Select]

[font=Courier]
 
| cos(T)  0 -sin(T)  0 |
|   0     1    0     0 |
| sin(T)  0  cos(T)  0 |
|   0     0    0     1 |
 
[/font]

And about the Z-axis
Code: [Select]

[font=Courier]
 
| cos(T)   sin(T)  0  0 |
| -sin(T)  cos(T)  0  0 |
|    0       0     1  0 |
|    0       0     0  1 |
 
[/font]

You can also multiply these matrices together to come up with a single matrix that does it all!  But the order that you multiply matrices DOES matter, so you generally want to  use the scale matrix first, multiply the rotation matrices next (in order X, Y, Z), and finally multiply the result by the translate matrix.  This will scale first, then rotate, and finally move an object, which is probably what you want.

I should also note that many other matrices can be applied to a vector.  A matrix that applies perspective, a matrix to twist or shear an object, basically anything you can deam of can be done with matrices!  Just do a search on the web for matrix transformations.

I hope that helps you understand how using matrices can help with 3D graphics.  Let me know if I can be of any further assistance.

Sidewinder
 

Offline GreatLorTopic starter

  • Jr. Member
  • **
  • Join Date: Apr 2004
  • Posts: 72
    • Show only replies by GreatLor
Re: I want an asm-float-routine
« Reply #7 on: June 09, 2004, 04:20:29 PM »
Thanks for your extensive explenation Sidewinder, however its RELLY hard to grasp the point of the system (the matrix that is), maybe I'll have easier understanding when I need a more sophisticated way to say, rotate the object not just around the local and absolute axii, but also around a arbitrary axis, whose algorithms I vill do soon.
So basically my brain finds mathemtical problems that are unpractical to my experiments distgusting ( :-( ), I dont know I've been like this as long as I can remember, only when I need to solve that problem in order to get something actually practical out of it, only then my interest awakes.

(damn I hate the word matrix more then ever now  :pissed: ...........  :-P )
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
Re: I want an asm-float-routine
« Reply #8 on: June 09, 2004, 05:39:36 PM »
Quote
GreatLor wrote:
Thanks for your extensive explenation Sidewinder, however its RELLY hard to grasp the point of the system (the matrix that is), maybe I'll have easier understanding when I need a more sophisticated way to say, rotate the object not just around the local and absolute axii, but also around a arbitrary axis, whose algorithms I vill do soon.
So basically my brain finds mathemtical problems that are unpractical to my experiments distgusting ( :-( ), I dont know I've been like this as long as I can remember, only when I need to solve that problem in order to get something actually practical out of it, only then my interest awakes.

Hrm. Whether you like it or not, fiddling with 3D in a computer involves a lot of math. In the good old days you could take shortcuts since you knew objects would be simple, and camera paths were hardcoded. That is a big nono now. If you do follow the ancient ways you get that rather nasty sounding tale you wrote about hardwiring shifts into numbers for quick multiplications. It may get the job done, but it will be hell to extend to other applications, much less explaining what you did to other people. Speaking for myself, I have mostly always next to no clue what you are trying to achieve.

Personally, I think you should for just this one time bite the bullet, and get down and dirty with matrix math and its application to 3D rendering before even writing a single letter of AMOS, much less assembly. In other words, switch off your Amiga, hop down to your local book store, and buy a book on 3D games programming, or applied maths for games programmers. They are terrific manuals, I've had them in my hands many times, and wondered why we never got this type of math in high school. Then write a few simple routines in AMOS to make sure you understand what you want the computer to calculate, and only then switch to assembly.

You cannot pick and mix with the maths in this subject: even if you know you can take shortcuts, you still have to know their details at heart. Jumping straight in also makes it very hard for us to help you with problems. And considering that 3D is not easy...
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
Re: I want an asm-float-routine
« Reply #9 on: June 09, 2004, 05:43:13 PM »
@GreatLor

I understand where you are coming from.  The jump from trig to linear algebra is a long one.  Matrix operations are not necessary for 3D graphics, but they do offer some speed gains as well as a more unified way of working with 3D concepts as long as you can understand what's going on.  Oh well, hopefully somebody learned something from my little tutorial.   :-)

Sidewinder
 

Offline DethKnight

  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 509
    • Show only replies by DethKnight
Re: I want an asm-float-routine
« Reply #10 on: June 09, 2004, 06:24:16 PM »
Quote
Oh well, hopefully somebody learned something from my little tutorial


dude, you just explained to me in ten minutes what my (h/s)  Advanced math teacher couldn't explain in one year.

Thx for that bit of enlightenment
wanted; NONfunctional A3K keyboard wanted
 

Offline GreatLorTopic starter

  • Jr. Member
  • **
  • Join Date: Apr 2004
  • Posts: 72
    • Show only replies by GreatLor
Re: I want an asm-float-routine
« Reply #11 on: June 10, 2004, 01:51:07 PM »
I dont mean that I dont get ANYTHING with matrices, what I mean is that I absoulutely NEED to know not HOW, but WHY forexample matrix products work (4 x 4 system in particular), you see I need the proofes (is it called axioms in math ?), I'm that sort of dude that REFUSE to do any form of calculation that I dont get, so what I want is an extensive (or short for that matter) text/article or whatever, that lightens up all forms of matrix-calculations (for my needs - 3d programing) as easy, obvious and clear as 3d-rotations are to me now, anyone who can guide/lead me into the "right" source of tutorial/text rocks !!!  :-)
 

Offline Sidewinder

  • Full Member
  • ***
  • Join Date: Mar 2002
  • Posts: 241
    • Show only replies by Sidewinder
    • http://www.liquido2.com
Re: I want an asm-float-routine
« Reply #12 on: June 10, 2004, 04:36:07 PM »
If you want proofs and such you'll really need to get a book on linear algebra.  I don't think any computer graphics book is going to go that in depth into the math.  Most assume that you know how to do the math.  However, one book that I have found that may be useful to you is "3D Math Primer for Graphics and Game Development".


Sidewinder
 

Offline GreatLorTopic starter

  • Jr. Member
  • **
  • Join Date: Apr 2004
  • Posts: 72
    • Show only replies by GreatLor
Re: I want an asm-float-routine
« Reply #13 on: June 11, 2004, 03:29:14 PM »
Thanx Sidewinder, I'll try to get a copy of that book !