/*
 
    Project  : H.264 encoder test    
 
    Module   : Tranform algorithms
 
 
 
    Author   : Marko 'Fador' Viitanen
 
 
 
    Date     : 27/6/2009
 
    Modified : 28/6/2009
 
*/
 
 
 
#include "common.h"
 
 
 
//Octave
 
//a=1/2
 
//b=sqrt(2/5)
 
//d=1/2
 
 
 
//E2=[a^2, a*b, a^2, a*b;a*b, b^2, a*b, b^2;a^2, a*b, a^2, a*b;a*b, b^2, a*b, b^2]
 
 
 
 
 
//4x4 Integer Cosine Transform
 
uint8 transform_4x4(sint32 *block, sint32 *target)
 
{
 
    sint32 helper[4*4];
 
    uint8 i;
 
 
 
    //[1, 1, 1, 1
 
    // 2, 1,-1,-2
 
    // 1,-1,-1, 1
 
    // 1,-2, 2,-1
 
    helper[0]=block[0]+block[4]+block[8]+block[12];
 
    helper[4]=2*block[0]+block[4]-block[8]-2*block[12];
 
    helper[8]=block[0]-block[4]-block[8]+block[12];
 
    helper[12]=block[0]-2*block[4]+2*block[8]-block[12];
 
 
 
    helper[1]=block[1]+block[5]+block[9]+block[13];
 
    helper[5]=2*block[1]+block[5]-block[9]-2*block[13];
 
    helper[9]=block[1]-block[5]-block[9]+block[13];
 
    helper[13]=block[1]-2*block[5]+2*block[9]-block[13];
 
 
 
    helper[2]=block[2]+block[6]+block[10]+block[14];
 
    helper[6]=2*block[2]+block[6]-block[10]-2*block[14];
 
    helper[10]=block[2]-block[6]-block[10]+block[14];
 
    helper[14]=block[2]-2*block[6]+2*block[10]-block[14];
 
 
 
    helper[3]=block[3]+block[7]+block[11]+block[15];
 
    helper[7]=2*block[3]+block[7]-block[11]-2*block[15];
 
    helper[11]=block[3]-block[7]-block[11]+block[15];
 
    helper[15]=block[3]-2*block[7]+2*block[11]-block[15];
 
 
 
    // [1, 2, 1, 1
 
    //  1, 1,-1,-2
 
    //  1,-1,-1, 2
 
    //  1,-2, 1,-1]
 
 
 
    target[0]=helper[0]+helper[1]+helper[2]+helper[3];
 
    target[1]=2*helper[0]+helper[1]-helper[2]-2*helper[3];
 
    target[2]=helper[0]-helper[1]-helper[2]+helper[3];
 
    target[3]=helper[0]-2*helper[1]+2*helper[2]-helper[3];
 
 
 
    target[4]=helper[4]+helper[5]+helper[6]+helper[7];
 
    target[5]=2*helper[4]+helper[5]-helper[6]-2*helper[7];
 
    target[6]=helper[4]-helper[5]-helper[6]+helper[7];
 
    target[7]=helper[4]-2*helper[5]+2*helper[6]-helper[7];
 
 
 
    target[8]=helper[8]+helper[9]+helper[10]+helper[11];
 
    target[9]=2*helper[8]+helper[9]-helper[10]-2*helper[11];
 
    target[10]=helper[8]-helper[9]-helper[10]+helper[11];
 
    target[11]=helper[8]-2*helper[9]+2*helper[10]-helper[11];
 
 
 
    target[12]=helper[12]+helper[13]+helper[14]+helper[15];
 
    target[13]=2*helper[12]+helper[13]-helper[14]-2*helper[15];
 
    target[14]=helper[12]-helper[13]-helper[14]+helper[15];
 
    target[15]=helper[12]-2*helper[13]+2*helper[14]-helper[15];
 
 
 
    //for(i=0;i<16;i++)
 
        //target[i]=round(target[i]*E_f[i]);
 
    return 1;
 
}
 
 
 
//4x4 Inverse Integer Cosine Transform
 
uint8 itransform_4x4(sint32 *block, sint32 *target)
 
{
 
    sint32 helper[4*4];
 
 
 
    uint8 i;
 
    //[1,  1,  1, 1/2
 
    // 1, 1/2,-1, -1
 
    // 1,-1/2,-1  ,1
 
    // 1, -1,  1,-1/2
 
    helper[0]=block[0]+block[4]+block[8]+block[12]/2;
 
    helper[4]=block[0]+block[4]/2-block[8]-block[12];
 
    helper[8]=block[0]-block[4]/2-block[8]+block[12];
 
    helper[12]=block[0]-block[4]+block[8]-block[12]/2;
 
 
 
    helper[1]=block[1]+block[5]+block[9]+block[13]/2;
 
    helper[5]=block[1]+block[5]/2-block[9]-block[13];
 
    helper[9]=block[1]-block[5]/2-block[9]+block[13];
 
    helper[13]=block[1]-block[5]+block[9]-block[13]/2;    
 
    
 
    helper[2]=block[2]+block[6]+block[10]+block[14]/2;
 
    helper[6]=block[2]+block[6]/2-block[10]-block[14];
 
    helper[10]=block[2]-block[6]/2-block[10]+block[14];
 
    helper[14]=block[2]-block[6]+block[10]-block[14]/2;    
 
    
 
    helper[3]=block[3]+block[7]+block[11]+block[15]/2;
 
    helper[7]=block[3]+block[7]/2-block[11]-block[15];
 
    helper[11]=block[3]-block[7]/2-block[11]+block[15];
 
    helper[15]=block[3]-block[7]+block[11]-block[15]/2;
 
 
 
    //for(i=0;i<16;i++)
 
        //helper[i]= round(helper[i]*E_i[i]);
 
 
 
    // [1,  1,   1,   1
 
    //  1, 1/2,-1/2,-1
 
    //  1, -1,  -1,   1
 
    //  1/2,-1,  1, -1/2]
 
 
 
    target[0]=(helper[0]+helper[1]+helper[2]+helper[3]/2);
 
    target[1]=(helper[0]+helper[1]/2-helper[2]-helper[3]);
 
    target[2]=(helper[0]-helper[1]/2-helper[2]+helper[3]);
 
    target[3]=(helper[0]-helper[1]+helper[2]-helper[3]/2);
 
 
 
    target[4]=(helper[4]+helper[5]+helper[6]+helper[7]/2);
 
    target[5]=(helper[4]+helper[5]/2-helper[6]-helper[7]);
 
    target[6]=(helper[4]-helper[5]/2-helper[6]+helper[7]);
 
    target[7]=(helper[4]-helper[5]+helper[6]-helper[7]/2);
 
 
 
    target[8]=(helper[8]+helper[9]+helper[10]+helper[11]/2);
 
    target[9]=(helper[8]+helper[9]/2-helper[10]-helper[11]);
 
    target[10]=(helper[8]-helper[9]/2-helper[10]+helper[11]);
 
    target[11]=(helper[8]-helper[9]+helper[10]-helper[11]/2);
 
 
 
    target[12]=(helper[12]+helper[13]+helper[14]+helper[15]/2);
 
    target[13]=(helper[12]+helper[13]/2-helper[14]-helper[15]);
 
    target[14]=(helper[12]-helper[13]/2-helper[14]+helper[15]);
 
    target[15]=(helper[12]-helper[13]+helper[14]-helper[15]/2);  
 
 
 
 
 
    return 1;
 
}
 
 
 
//4x4 Hadamard transformation
 
uint8 transformDC_4x4(sint32 *block, sint32 *target)
 
{
 
    sint32 helper[4*4];
 
 
 
    //[1,  1,  1,  1
 
    // 1,  1, -1, -1
 
    // 1, -1, -1  ,1
 
    // 1, -1,  1, -1
 
    helper[0]=block[0]+block[4]+block[8]+block[12];
 
    helper[4]=block[0]+block[4]-block[8]-block[12];
 
    helper[8]=block[0]-block[4]-block[8]+block[12];
 
    helper[12]=block[0]-block[4]+block[8]-block[12];
 
 
 
    helper[1]=block[1]+block[5]+block[9]+block[13];
 
    helper[5]=block[1]+block[5]-block[9]-block[13];
 
    helper[9]=block[1]-block[5]-block[9]+block[13];
 
    helper[13]=block[1]-block[5]+block[9]-block[13];    
 
    
 
    helper[2]=block[2]+block[6]+block[9]+block[14];
 
    helper[6]=block[2]+block[6]-block[9]-block[14];
 
    helper[10]=block[2]-block[6]-block[9]+block[14];
 
    helper[14]=block[2]-block[6]+block[9]-block[14];    
 
    
 
    helper[3]=block[3]+block[7]+block[10]+block[15];
 
    helper[7]=block[3]+block[7]-block[10]-block[15];
 
    helper[11]=block[3]-block[7]-block[10]+block[15];
 
    helper[15]=block[3]-block[7]+block[10]-block[15];
 
 
 
 
 
    //[1,  1,  1,  1
 
    // 1,  1, -1, -1
 
    // 1, -1, -1  ,1
 
    // 1, -1,  1, -1
 
 
 
    target[0]=round(helper[0]+helper[1]+helper[2]+helper[3])>>1;
 
    target[1]=round(helper[0]+helper[1]-helper[2]-helper[3])>>1;
 
    target[2]=round(helper[0]-helper[1]-helper[2]+helper[3])>>1;
 
    target[3]=round(helper[0]-helper[1]+helper[2]-helper[3])>>1;
 
 
 
    target[4]=round(helper[4]+helper[5]+helper[6]+helper[7])>>1;
 
    target[5]=round(helper[4]+helper[5]-helper[6]-helper[7])>>1;
 
    target[6]=round(helper[4]-helper[5]-helper[6]+helper[7])>>1;
 
    target[7]=round(helper[4]-helper[5]+helper[6]-helper[7])>>1;
 
 
 
    target[6]=round(helper[8]+helper[9]+helper[10]+helper[11])>>1;
 
    target[9]=round(helper[8]+helper[9]-helper[10]-helper[11])>>1;
 
    target[10]=round(helper[8]-helper[9]-helper[10]+helper[11])>>1;
 
    target[11]=round(helper[8]-helper[9]+helper[10]-helper[11])>>1;
 
 
 
    target[12]=round(helper[12]+helper[13]+helper[14]+helper[15])>>1;
 
    target[13]=round(helper[12]+helper[13]-helper[14]-helper[15])>>1;
 
    target[14]=round(helper[12]-helper[13]-helper[14]+helper[15])>>1;
 
    target[15]=round(helper[12]-helper[13]+helper[14]-helper[15])>>1;  
 
 
 
 
 
    return 1;
 
 
 
 
 
}
 
 
 
 
 
//2x2 Hadamard transformation
 
uint8 transformDC_2x2(sint32 *block, sint32 *target)
 
{
 
    sint32 helper[2*2];
 
 
 
    //[1,  1,
 
    // 1,  -1]
 
 
 
    helper[0]=block[0]+block[2];
 
    helper[2]=block[0]-block[2];
 
 
 
    helper[1]=block[1]+block[3];
 
    helper[3]=block[1]-block[3];
 
 
 
    //[1,  1,
 
    // 1,  -1]
 
 
 
    target[0]=round(helper[0]+helper[1])>>1;
 
    target[1]=round(helper[0]+helper[1])>>1;
 
 
 
    target[2]=round(helper[2]-helper[3])>>1;
 
    target[3]=round(helper[2]-helper[3])>>1;
 
 
 
    return 1;
 
 
 
}