/*
 *  Matrix.h
 *  
 *
 *  Created by tristan on Sat Aug 24 2002.
 *  Copyright (c) 2001 __MyCompanyName__. All rights reserved.
 *
 */
 
////////////////////////////////////////////////////////////////////////////////////////
// Utility Functions
////////////////////////////////////////////////////////////////////////////////////////
#define FLOAT_ALIGNMENT 0x00000003
// 23 bit mantisa on a float (we need error for checking if two nums are equal)
// for now use error of 1/2^18, this could be refined up to 1/2^22 if needed
#define FLOATING_POINT_ERROR (1.0f/262144.0f)
// check if two numbers are approximately equal, used when floating point errors
// occur.  Should NEVER check to see if two floats are identical
inline bool approxEqual(float a, float b)
{
    a -= b;
    a = (a < 0) ? -a: a;
    return (a < FLOATING_POINT_ERROR);
}
float determinant (const float * matrix , int side);
void subMatrix    (const float * src, int side, float * dst , int col_omit, int row_omit);
///////////////////////////////////////////////////////////////////////////////////////
// Matrix
//////////////////////////////////////////////////////////////////////////////////////
class Matrix
{
    protected:
        float * transpose_record;		// to use while transposing the record
    public:
        char * address;		// the start of the data
        jint stride;		// the distance between each record   
        jint 	 width, 	// the width of the matrix
                 height, 	// the height of the matrix
                 elements;	// the number of matricies
        jboolean transpose;	// whether this matrix is or will be transposed
       
        Matrix (jint a, jint s, jint e):
            address((char *)a), stride(s), elements(e) {}
        bool identicalDataSpaces   (Matrix & other);
        bool intersectingDataSpaces(Matrix & other);
        void transposeMatrix(float * src, float * dst, int src_width, int src_height);
        void transposeMatrix(float * mat, int src_width, int src_height);
};
///////////////////////////////////////////////////////////////////////////////////////
// Src Matrix
//////////////////////////////////////////////////////////////////////////////////////
class MatrixSrc: public Matrix
{
    private:
        char * record_offset;		// the offset of this record in memory
    
        float * record;			// temporary storage to store a fully aligned and transposed
                                        // copy of the record, if the one in memory is not so
        float * current_record_ptr;	// the address of the memory containing the record last
                                        // returned by the nextMatrix() function
        jint record_size;		// the total floats in each record
    public:
        MatrixSrc ( jint address, jint stride, jint width, jint height, jint elements, jboolean transpose);
        ~MatrixSrc();
        
        void rewind() {	record_offset = address; }
        float * nextMatrix();
};
///////////////////////////////////////////////////////////////////////////////////////
// Dst Matrix
//////////////////////////////////////////////////////////////////////////////////////
class MatrixDst: public Matrix
{
    private:
        char  * record_offset;	// the offset of the record in memory
    
        jboolean data_buffered;	// if all of the data has to be buffered
        char * buffer;		// a buffer used when data_buffered
        
        jboolean last_record_in_temp;
        jboolean record_buffered;	// if only a single record is buffered
        float * record;		// to store data if source is unaligned
        
        jint record_size;
        void createBuffer();
    public:
        MatrixDst (jint address, jint stride, jint width, jint height, jint elements, jboolean transpose);
        ~MatrixDst();
        void configureBuffer(MatrixSrc & a, MatrixSrc & b);        
        void configureBuffer(MatrixSrc & a);    
        
        float * nextMatrix();
        void writeComplete();
};