/*
 * DMLib
 * -- Vector and matrix functions
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
 */
#ifndef DMVECMAT_H
#define DMVECMAT_H
#include "dmlib.h"

#include <math.h>

#ifdef __cplusplus
extern "C" {
#endif

#define DM_MATRIX_SIZE	(4)

typedef struct
{
    DMFloat x, y, z, W;
} DMVector;

typedef	struct
{
    DMFloat m[DM_MATRIX_SIZE][DM_MATRIX_SIZE];
} DMMatrix;


void    dm_vector_add_n(DMVector *dst, const DMVector *src, const int nlist);
void    dm_vector_add_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist);
void    dm_vector_sub_n(DMVector *dst, const DMVector *src, const int nlist);
void    dm_vector_sub_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist);

void    dm_vector_mul_by_mat(DMVector *vd, const DMVector *vs, const DMMatrix *mat);
void    dm_vector_mul_by_mat_n(DMVector *list, const int nlist, const DMMatrix *mat);

void    dm_matrix_unit(DMMatrix *mat);
void    dm_matrix_transpose(DMMatrix *mat1, const DMMatrix *mat2);

void    dm_matrix_mul(DMMatrix *mat1, const DMMatrix *mat2);
void    dm_matrix_mul_r(DMMatrix *dst, const DMMatrix *mat1, const DMMatrix *mat2);
void    dm_matrix_mul_n(DMMatrix *list, const int nlist, const DMMatrix *mat);

void    dm_matrix_rot(DMMatrix *mat,
        const DMFloat sx, const DMFloat sy, const DMFloat sz,
        const DMFloat cx, const DMFloat cy, const DMFloat cz);


/* Basic vector operations
 */
static inline void dm_vector_copy(DMVector *vd, const DMVector *vs)
{
    memcpy(vd, vs, sizeof(DMVector));
}


static inline void dm_vector_add(DMVector *vr, const DMVector *v2)
{
    vr->x += v2->x;
    vr->y += v2->y;
    vr->z += v2->z;
}


static inline void dm_vector_add_r(DMVector *vr, const DMVector *v1, const DMVector *v2)
{
    vr->x = v1->x + v2->x;
    vr->y = v1->y + v2->y;
    vr->z = v1->z + v2->z;
}


static inline void dm_vector_sub(DMVector *vr, const DMVector *v2)
{
    vr->x -= v2->x;
    vr->y -= v2->y;
    vr->z -= v2->z;
}


static inline void dm_vector_sub_r(DMVector *vr, const DMVector *v1, const DMVector *v2)
{
    vr->x = v1->x - v2->x;
    vr->y = v1->y - v2->y;
    vr->z = v1->z - v2->z;
}


/* Returns dot-product of two given vectors
 */
static inline DMFloat dm_vector_dot(const DMVector *v1, const DMVector *v2)
{
    return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z);
}


/* Return vector length
 */
static inline DMFloat dm_vector_length(const DMVector *vs)
{
    return sqrt((vs->x * vs->x) + (vs->y * vs->y) + (vs->z * vs->z));
}


/* Normalize vector
 */
static inline void dm_vector_normalize(DMVector *vec)
{
    DMFloat l = dm_vector_length(vec);

    if (l > 0.0f)
    {
        l = 1.0f / l;
        vec->x *= l;
        vec->y *= l;
        vec->z *= l;
    }
}


/* Scale given vector
 */
static inline void dm_vector_scale(DMVector * vec, const DMFloat k)
{
    vec->x *= k;
    vec->y *= k;
    vec->z *= k;
}


/* Returns cross-product of two given vectors
 */
static inline void dm_vector_cross(DMVector *vr, const DMVector *v1, const DMVector *v2)
{
    vr->x = (v1->y * v2->z) - (v1->z * v2->y);
    vr->y = (v1->z * v2->x) - (v1->x * v2->z);
    vr->z = (v1->x * v2->y) - (v1->y * v2->x);
}


/* Make rotation matrix from given angles (radians)
 */
static inline void dm_matrix_rot_a(DMMatrix *mat, const DMFloat ax, const DMFloat ay, const DMFloat az)
{
    dm_matrix_rot(mat, sin(ax), sin(ay), sin(az), cos(ax), cos(ay), cos(az));
}


#ifdef __cplusplus
}
#endif
#endif // DMVECMAT_H
