# vmath (lxvmath.h)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

## Vectors

The tree-dimensional data types used in this implementation are normally arrays of size three. Algorithms often loop over the three indices, so there are a lot of "3"'s sprinkled about the code. I define the number of dimensions here as a constant just to make the usages more descriptive and explicit than the naked "3". The value of this constant will never change.

##### (1) SDK: LXdND define (ref types)
` #define LXdND            3`

Some definitions for vectors with different underlying types. The indices are 0=X, 1=Y, 2=Z.

##### (2) SDK: Types
``` typedef double           LXtVector[LXdND];
typedef float           LXtFVector[LXdND];
typedef short           LXtSVector[LXdND];
typedef unsigned int    LXtUVector[LXdND];
typedef double           LXtVector2[2];
typedef float           LXtFVector2[2];
typedef unsigned int    LXtUVector2[2];
typedef double           LXtVector4[4];
typedef float           LXtFVector4[4];
typedef unsigned int    LXtUVector4[4];```

Since vectors can have double and single precision forms, and since vector operations are often small, repetitive mathematical calculations which are highly amenable to optimization, most basic vector ops are coded as macros. The macro form allows arguments to have mixed types, and the in-line code thus generated should be about as fast as possible. To make things easier for the programmer, the macros are coded using the slightly confusing 'comma operator' which allows the multiple assignments to be performed as a single expression. These macros can therefore be used as if they were single atomic operations regardless of context.

### Unary Operations

 VCLR(a) This assigns all three components of the vector 'a' to zero. VSET(a,x) This assigns all three components of the vector 'a' to the scalar value 'x'. VSET3(a,x,y,z) This assigns three components of the vector 'a' to the different scalar values 'x', 'y', and 'z'. VEQS(a,x) This is true if all three components of the vector 'a' are equal to the scalar value 'x'. VUNIT(a,k) This makes a unit vector in one of the primary axes, given by k in [0..2]. VNEG(a) This negates each of the vector components. VUOP(a,op) General Vector Unary OPerator. It does a[i]=op(a[i]) for all components. Op can be any unary operator, such as ABS() or floor(). VUOP2(a,b,op) Same as the above, but the output is placed into the first vector: a[i]=op(b[i]). V1MIN(a,x) This sets each component of 'a' to the minimum of itself and the scalar value 'x'. V1MAX(a,x) This sets each component of 'a' to the maximum of itself and the scalar value 'x'. VNEZERO(a) This is true if one of components of the vector 'a' is not 0.
##### (3) Unary \$\$ macros
``` #define \$\$VCLR(a)               \$\$VSET(a,0.0)
#define \$\$VSET(a,x)             ((a)[0]=(x), (a)[1]=(x), (a)[2]=(x))
#define \$\$VSET3(a,x,y,z)        ((a)[0]=(x), (a)[1]=(y), (a)[2]=(z))
#define \$\$VEQS(a,x)             ((a)[0]==(x) && (a)[1]==(x) && (a)[2]==(x))
#define \$\$VUNIT(a,k)            (\$\$VCLR(a), (a)[k] = 1.0)
#define \$\$VNEG(v)               ((v)[0] = -((v)[0]), (v)[1] = -((v)[1]), (v)[2] = -((v)[2]))
#define \$\$VUOP(v,op)            ((v)[0] = op((v)[0]), (v)[1] = op((v)[1]), (v)[2] = op((v)[2]))
#define \$\$VUOP2(x,v,op)         ((x)[0] = op((v)[0]), (x)[1] = op((v)[1]), (x)[2] = op((v)[2]))
#define \$\$V1MIN(a,x)            ((a)[0]=(a)[0]>(x) ? (x):(a)[0],\
(a)[1]=(a)[1]>(x) ? (x):(a)[1],\
(a)[2]=(a)[2]>(x) ? (x):(a)[2])
#define \$\$V1MAX(a,x)            ((a)[0]=(a)[0]<(x) ? (x):(a)[0],\
(a)[1]=(a)[1]<(x) ? (x):(a)[1],\
(a)[2]=(a)[2]<(x) ? (x):(a)[2])
#define \$\$VNEZERO(a)            ((a)[0] || (a)[1] || (a)[2])```

The '\$\$' in the code fragment above is replaced with 'LXx_' in all the SDK headers. This allows the same macros to have slightly different forms in different contexts.

##### (4) SDK: Declarations
` ''[[#C3|Unary LXx_ macros]]''`

This is an obsolete form that is also supported for legacy reasons.

##### (5) SDK: LXx_V3SET define
` #define LXx_V3SET(a,x,y,z)      LXx_VSET3(a,x,y,z)`

### Binary Operations

 VEQ(a,b) This expression is true if the components of vector 'a' equal those of 'b'. VCPY(a,b) This assigns the vector 'a' to have the same value as the vector 'b'. VSCL(a,x) This multiplies the vector 'a' by the scalar 'x', storing the result in 'a'. VADD(a,b) This adds the vector 'b' to the vector 'a', storing the result in 'a'. VSUB(a,b) This subtracts the vector 'b' from the vector 'a', storing the result in 'a'. VADDS(a,b,x) This multiplies the vector 'b' by the scalar 'x' and then adds it to 'a'. The result is stored in the vector 'a'. VMUL(a,b) This multiplies the vector 'a' by the vector 'b'. The result is stored in the vector 'a'. VDIV(a,b) This divides the vector 'a' by the vector 'b'. The result is stored in the vector 'a'. VBOP(a,b,op) General Vector Binary OPerator. The performs the given binary operator (like MAX() or MIN()) on each component of 'a' and 'b' as a pair, and stores the result in 'a'. V3MIN(a,x) This sets each component of 'a' to the minimum of itself and the corresponding component of the vector 'x'. V3MAX(a,x) This sets each component of 'a' to the maximum of itself and the corresponding component of the vector 'x'.
##### (6) Binary \$\$ macros
``` #define \$\$VEQ(a,b)              ((a)[0]==(b)[0]&&(a)[1]==(b)[1]&&(a)[2]==(b)[2])
#define \$\$VCPY(a,b)             ((a)[0] =(b)[0], (a)[1] =(b)[1], (a)[2] =(b)[2])
#define \$\$VSCL(a,x)             ((a)[0]*= (x),   (a)[1]*= (x),   (a)[2]*= (x))
#define \$\$VSUB(a,b)             ((a)[0]-=(b)[0], (a)[1]-=(b)[1], (a)[2]-=(b)[2])
#define \$\$VMUL(a,b)             ((a)[0] *=(b)[0], (a)[1] *=(b)[1], (a)[2] *=(b)[2])
#define \$\$VDIV(a,b)             ((a)[0] /=(b)[0], (a)[1] /=(b)[1], (a)[2] /=(b)[2])
#define \$\$VBOP(a,b,op)          ((a)[0]=op((a)[0],(b)[0]), (a)[1]=op((a)[1],(b)[1]), (a)[2]=op((a)[2],(b)[2]))
#define \$\$V3MIN(a,b)            \$\$VBOP(a,b,LXxMIN)
#define \$\$V3MAX(a,b)            \$\$VBOP(a,b,LXxMAX)
#define \$\$V2CPY(a,b)             ((a)[0] =(b)[0], (a)[1] =(b)[1])
#define \$\$V2SCL(a,x)             ((a)[0]*= (x),   (a)[1]*= (x))
#define \$\$V2SUB(a,b)             ((a)[0]-=(b)[0], (a)[1]-=(b)[1])
#define \$\$V2MUL(a,b)             ((a)[0] *=(b)[0], (a)[1] *=(b)[1])
#define \$\$V2DIV(a,b)             ((a)[0] /=(b)[0], (a)[1] /=(b)[1])
#define \$\$V2BOP(a,b,op)          ((a)[0]=op((a)[0],(b)[0]), (a)[1]=op((a)[1],(b)[1]))```

##### (7) SDK: Declarations
` ''[[#C6|Binary LXx_ macros]]''`

### Trinary Operations

 VADD3(r,a,b) This adds the vector 'b' to the vector 'a', storing the result in 'r'. VADDS3(r,a,b,x) This multiplies the vector 'b' by the scalar 'x' and then adds it to 'a'. The result is stored in the vector 'r'. VSUB3(r,a,b) This subtracts the vector 'b' from the vector 'a', storing the result in 'r'. VSCL3(r,a,x) This multiplies the vector 'a' by the scalar 'x', storing the result in 'r'. VMUL3(r,a,b) This multiplies the vector 'b' by the vector 'a'. The result is stored in the vector 'r'. VBOP3(r,a,b,op) General Vector Binary OPerator. The performs the given operator on each component of 'a' and 'b' as a pair, and stores the result in 'r'. VMIN3(r,a,b) Store the minimum of each component of 'a' and 'b' in 'r'. VMAX3(r,a,b) Store the maximum of each component of 'a' and 'b' in 'r'.
##### (8) Trinary \$\$ macros
``` #define \$\$VADD3(r,a,b)          ((r)[0]=(a)[0]+(b)[0], (r)[1]=(a)[1]+(b)[1], (r)[2]=(a)[2]+(b)[2])
#define \$\$VSUB3(r,a,b)          ((r)[0]=(a)[0]-(b)[0], (r)[1]=(a)[1]-(b)[1], (r)[2]=(a)[2]-(b)[2])
#define \$\$VSCL3(r,a,x)          ((r)[0]=(a)[0]*(x),    (r)[1]=(a)[1]*(x),    (r)[2]=(a)[2]*(x))
#define \$\$VMUL3(r,a,b)          ((r)[0]=(a)[0]*(b)[0], (r)[1]=(a)[1]*(b)[1], (r)[2]=(a)[2]*(b)[2])
#define \$\$VBOP3(r,a,b,op)       ((r)[0]=op((a)[0],(b)[0]), (r)[1]=op((a)[1],(b)[1]), (r)[2]=op((a)[2],(b)[2]))
#define \$\$VMIN3(r,a,b)          \$\$VBOP3(r,a,b,LXxMIN)
#define \$\$VMAX3(r,a,b)          \$\$VBOP3(r,a,b,LXxMAX)
#define \$\$V2SUB3(r,a,b)          ((r)[0]=(a)[0]-(b)[0], (r)[1]=(a)[1]-(b)[1])
#define \$\$V2SCL3(r,a,x)          ((r)[0]=(a)[0]*(x),    (r)[1]=(a)[1]*(x))
#define \$\$V2MUL3(r,a,b)          ((r)[0]=(a)[0]*(b)[0], (r)[1]=(a)[1]*(b)[1])
#define \$\$V2MIN3(r,a,b)         \$\$V2BOP3(r,a,b,LXxMIN)
#define \$\$V2MAX3(r,a,b)         \$\$V2BOP3(r,a,b,LXxMAX)```

##### (9) SDK: Declarations
` ''[[#C8|Trinary LXx_ macros]]''`

### RGBA Operations

RGBA macros deal with four component vectors and start with "V4". In general they follow the exact same pattern as the "V" macros, although not all the cases may be supported.

 V4BLACK(a) This sets the RGBA color to black with an alpha of 1. V4ZERO(a) This sets the RGBA color to black with a zero alpha.
##### (10) RGBA \$\$ macros
``` #define \$\$V4BLACK(a)            \$\$V4SET4(a,0,0,0,1)
#define \$\$V4ZERO(a)             \$\$V4SET4(a,0,0,0,0)
#define \$\$V4SET(a,x)            \$\$V4SET4(a,x,x,x,x)
#define \$\$V4SET4(a,x,y,z,w)     ((a)[0] =(x),               (a)[1] =(y),               (a)[2] =(z),               (a)[3] =(w))
#define \$\$V4CPY(a,b)            ((a)[0] =(b)[0],            (a)[1] =(b)[1],            (a)[2] =(b)[2],            (a)[3] =(b)[3])
#define \$\$V4ADD(a,b)            ((a)[0]+=(b)[0],            (a)[1]+=(b)[1],            (a)[2]+=(b)[2],            (a)[3]+=(b)[3])
#define \$\$V4ADD3(r,a,b)         ((r)[0] =(a)[0]+(b)[0],     (r)[1] =(a)[1]+(b)[1],     (r)[2] =(a)[2]+(b)[2],     (r)[3] =(a)[3]+(b)[3])
#define \$\$V4ADDS(a,b,x)         ((a)[0]+=(b)[0]*(x),        (a)[1]+=(b)[1]*(x),        (a)[2]+=(b)[2]*(x),        (a)[3]+=(b)[3]*(x))
#define \$\$V4ADDS3(r,a,b,x)      ((r)[0] =(a)[0]+(b)[0]*(x), (r)[1] =(a)[1]+(b)[1]*(x), (r)[2] =(a)[2]+(b)[2]*(x), (r)[3] =(a)[3]+(b)[3]*(x))
#define \$\$V4SUB(a,b)            ((a)[0]-=(b)[0],            (a)[1]-=(b)[1],            (a)[2]-=(b)[2],            (a)[3]-=(b)[3])
#define \$\$V4SCL(a,x)            ((a)[0]*=(x),               (a)[1]*=(x),               (a)[2]*=(x),               (a)[3]*=(x))
#define \$\$V4SCL3(r,a,x)         ((r)[0] =(a)[0]*(x),        (r)[1] =(a)[1]*(x),        (r)[2] =(a)[2]*(x),        (r)[3] =(a)[3]*(x))
#define \$\$V4DOT(a,b)            ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3])
#define \$\$V4EQ(a,b)             ((a)[0]==(b)[0]&&(a)[1]==(b)[1]&&(a)[2]==(b)[2]&&(a)[3]==(b)[3])```

##### (11) SDK: Declarations
` ''[[#C10|RGBA LXx_ macros]]''`

### Special Operations

 VDOT(a,b) This expression returns the dot product of vectors 'a' and 'b'. VDOT3(a,x,y,z) This expression returns the dot product of vector 'a' with the vector whose components are 'x', 'y', and 'z'. VLEN(a) This expression returns the length of the vector 'a'. VDIST(a,b), VDIST2(a,b) These expressions returns the distance between two positional vectors 'a' and 'b', and the distance squared. VCROSS(r,a,b) This computes the cross product 'a x b' and places the result in the vector 'r'. VLERP(r,a,b,c) This linearly interpolates between vectors 'a' and 'b' by the fraction 'c', storing the result in 'r'. VLERP_TO(r,a,b,c) This linearly interpolates between vector 'a' and scalar 'b' by the fraction 'c', storing the result in 'r'. VLERP_FROM(r,a,b,c) This linearly interpolates between scalar 'a' and vector 'b' by the fraction 'c', storing the result in 'r'. V4LERP(r,a,b,c) Same as VLERP, but performs the interpolation over four components, as for colors. LUMAFV(a) This returns the luminosity of an rgb[] vector. COMPOSE_RGB(v,v1,v2,alpha) This composes two RGB vectors with an alpha channel: v = v1*(1-alpha) + v2*alpha. HP_TO_VECTOR(v,h,p) This converts (Heading,Pitch) angular coordinates to a direction vector. Angles are expressed in radians. BYTE_FRACTION This simply the precomputed value of 1/255, which is quite useful when working with both 8-bit and floating point colors. BYTE_TO_FLOAT(b) This macro uses the BYTE_FRACTION value and includes the proper cast to ensure that the integer multiply does not always yield 0. FLOAT_TO_BYTE(f) This converts a floating-point color component into 8-bit form, using Dnint() for rounding. VPERP(a,b) This macro constructs a vector perpendicular to vector 'b' in vector 'a' by simply enforcing the orthogonality condition VDOT(a, b) == 0. This macro will not preserve normalization, and may create a zero length vector.
##### (12) Special \$\$ macros
``` #define \$\$VDOT(a,b)             ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2])
#define \$\$VDOT3(a,x,y,z)        ((a)[0]*(x)    + (a)[1]*(y)    + (a)[2]*(z))
#define \$\$VLEN(a)               sqrt (\$\$VDOT(a,a))
#define \$\$VLENSQ(a)             \$\$VDOT(a,a)
#define \$\$VDIST(a,b)            sqrt (\$\$VDIST2(a,b))
#define \$\$VDIST2(a,b)           ( ((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) +\
((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) +\
((a)[2] - (b)[2]) * ((a)[2] - (b)[2]) )
#define \$\$VCROSS(r,a,b)         ( (r)[0] = (a)[1]*(b)[2] - (a)[2]*(b)[1],\
(r)[1] = (a)[2]*(b)[0] - (a)[0]*(b)[2],\
(r)[2] = (a)[0]*(b)[1] - (a)[1]*(b)[0] )
#define \$\$VLERP(r,a,b,c)        ( (r)[0] = (a)[0] + (c)*((b)[0] - (a)[0]),\
(r)[1] = (a)[1] + (c)*((b)[1] - (a)[1]),\
(r)[2] = (a)[2] + (c)*((b)[2] - (a)[2]) )
#define \$\$VLERP_TO(r,a,b,c)     ( (r)[0] = (a)[0] + (c)*((b) - (a)[0]),\
(r)[1] = (a)[1] + (c)*((b) - (a)[1]),\
(r)[2] = (a)[2] + (c)*((b) - (a)[2]) )
#define \$\$VLERP_FROM(r,a,b,c)   ( (r)[0] = (a) + (c)*((b)[0] - (a)),\
(r)[1] = (a) + (c)*((b)[1] - (a)),\
(r)[2] = (a) + (c)*((b)[2] - (a)) )
#define \$\$V4LERP(r,a,b,c)       ( (r)[0] = (a)[0] + (c)*((b)[0] - (a)[0]),\
(r)[1] = (a)[1] + (c)*((b)[1] - (a)[1]),\
(r)[2] = (a)[2] + (c)*((b)[2] - (a)[2]),\
(r)[3] = (a)[3] + (c)*((b)[3] - (a)[3]) )
#define \$\$LUMAFV(a)             (0.30f * a[0] + 0.59f * a[1] + 0.11f * a[2])

#define \$\$COMPOSE_RGB(a,b,c,d)  ( (a)[0] = (b)[0]*(1 - (d)) + (c)[0]*(d),\
(a)[1] = (b)[1]*(1 - (d)) + (c)[1]*(d),\
(a)[2] = (b)[2]*(1 - (d)) + (c)[2]*(d) )

#define \$\$HP_TO_VECTOR(v,h,p)   ( (v)[2] = cos((p)),\
(v)[0] = cos((h))*(v)[2],\
(v)[1] = sin((p)),\
(v)[2]*= sin((h)) )

#define \$\$BYTE_FRACTION         (0.003921568627451f)
#define \$\$BYTE_TO_FLOAT(b)      ((float)(b) * \$\$BYTE_FRACTION)
#define \$\$FLOAT_TO_BYTE(f)      ((unsigned char) Dnint ((f) * 255.0))

#define \$\$VPERP(a,b)            ( (a)[0]=((b)[1]-(b)[2]), (a)[1]=((b)[2]-(b)[0]), (a)[2]=((b)[0]-(b)[1]) )

#define \$\$V2DOT(a,b)             ((a)[0]*(b)[0] + (a)[1]*(b)[1])
#define \$\$V2LEN(a)               sqrt (\$\$V2DOT(a,a))
#define \$\$V2LENSQ(a)             \$\$V2DOT(a,a)
#define \$\$V2DIST(a,b)            sqrt (\$\$V2DIST2(a,b))
#define \$\$V2DIST2(a,b)           ( ((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) )
#define \$\$V2PERP(a,b)            ( (a)[0]=-(b)[1], (a)[1]=(b)[0] )```

##### (13) SDK: Declarations
` ''[[#C12|Special LXx_ macros]]''`

##### (14) SDK: LXxMAX, etc. defines
``` #define LXxMAX(a,b)             ((a) > (b) ? (a) : (b))
#define LXxMIN(a,b)             ((a) <= (b) ? (a) : (b))
#define LXxCLAMP(a,b,c)         (((a) < (b)) ? (b) : (((a) > (c)) ? (c) : (a)))
#define LXxABS(a)               ((a) < 0 ? -(a) : (a))
#define LXxSIGN(a)              ((a) < 0 ? -1 : 1)```