/********************************************************************************************
   _____       _____       _     _____                _                    
  / ____|     |  __ \     | |   |  __ \              | |                   
 | |  ____  __| |__) |__ _| |__ | |__) |___ _ __   __| | ___ _ __ ___ _ __ 
 | | |_ \ \/ /|  _  // _` | '_ \|  _  // _ \ '_ \ / _` |/ _ \ '__/ _ \ '__|
 | |__| |>  < | | \ \ (_| | |_) | | \ \  __/ | | | (_| |  __/ | |  __/ |   
  \_____/_/\_\|_|  \_\__, |_.__/|_|  \_\___|_| |_|\__,_|\___|_|  \___|_|   
                      __/ |                                                
                     |___/           
GRRLIB Version : 1.6 Cut

Coder : NoNameNo
	uschghost
Cut: nullEX has deleted all funcitons... sorry!

info : http://wiibrew.org/index.php?title=Homebrew_apps/GRRLIB                   
********************************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc.h>


u16 *GRRLIB_buffer;
u16 GRRLIB_magenta=0xf01e;


void GRRLIB_FillScreen(u16 color){
        int x;
        for(x=0;x<640*480;x++){
                GRRLIB_buffer[x]=color;
        }
}
void GRRLIB_PutPixel(int x,int y, u16 color){
        if(((x>=0) & (x<640)) & ((y>=0) & (y<480))){
                GRRLIB_buffer[y*640+x]=color;
        }
}
u16 GRRLIB_Conv888_565(u8 r, u8 g, u8 b){
	u16 colorout;

	r = (r*31)/255;
	g = (g*63)/255;
	b = (b*31)/255;
	colorout=(((r<<6)|g)<<5)|b;

	return(colorout);	
}
//********************************************************************************************
// ALL CODE ABOVE THIS LINE IS THE "GX RGB RENDERER" CORE !!!!!!!!!!!!!!!!!!!! DONT TOUCH !!!!
//********************************************************************************************

#define DEFAULT_FIFO_SIZE (256 * 1024)

#define HASPECT 80
#define VASPECT 60

static u32 whichfb;
static u32 *xfb[2];
static GXRModeObj *vmode;

static u8 *gp_fifo;

static u8 *texturemem;
static u32 texturesize;

GXTexObj texobj;
static Mtx view;
static u16 vwidth, vheight, oldvwidth, oldvheight;

typedef struct tagcamera {
        Vector pos;
        Vector up;
        Vector view;
} camera;

static s16 square[] ATTRIBUTE_ALIGN(32) = {
        -HASPECT, VASPECT, 0,     // 0
        HASPECT, VASPECT, 0,      // 1
        HASPECT, -VASPECT, 0,     // 2
        -HASPECT, -VASPECT, 0,    // 3
};

static camera cam = {
        { 0.0f, 0.0f, 0.0f },
        { 0.0f, 0.5f, 0.0f },
        { 0.0f, 0.0f, -0.5f }
};

void GRRLIB_InitVideo () {
//        switch (VIDEO_GetCurrentTvMode()) {
//                case VI_NTSC:
//                        vmode = &TVNtsc480IntDf;
//                        break;
//                case VI_PAL:
//                        vmode = &TVPal528IntDf;
//                        break;
//                case VI_MPAL:
//                        vmode = &TVMpal480IntDf;
//                        break;
//                case VI_EURGB60:
//                        vmode = &TVNtsc480Prog;
//                        break;
//              default:
//                        vmode = &TVNtsc480IntDf;
//                        break;
//        }
//#ifdef FORZE_PAL60
//		extern GXRModeObj TVEurgb60Hz480IntDf;
//		vmode = &TVEurgb60Hz480IntDf;
//#endif
	vmode = VIDEO_GetPreferredMode(vmode);
        VIDEO_Configure (vmode);

        xfb[0] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode));
        xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode));
        gp_fifo = (u8 *) memalign (32, DEFAULT_FIFO_SIZE);

        VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK);
        VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK);

        whichfb = 0;
        VIDEO_SetNextFramebuffer (xfb[whichfb]);
        VIDEO_SetBlack (FALSE);
        VIDEO_Flush ();
        VIDEO_WaitVSync ();

        if (vmode->viTVMode & VI_NON_INTERLACE)
                VIDEO_WaitVSync ();
}

static void draw_init (void) {
        GX_ClearVtxDesc ();
        GX_SetVtxDesc (GX_VA_POS, GX_INDEX8);
        GX_SetVtxDesc (GX_VA_CLR0, GX_INDEX8);
        GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);

        GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
        GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
        GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);

        GX_SetArray (GX_VA_POS, square, 3 * sizeof (s16));

        GX_SetNumTexGens (1);
        GX_SetTexCoordGen (GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);

        GX_InvalidateTexAll ();

        GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
}

static void draw_vert (u8 pos, u8 c, f32 s, f32 t) {
        GX_Position1x8 (pos);
        GX_Color1x8 (c);
        GX_TexCoord2f32 (s, t);
}

static void draw_square (Mtx v) {
        Mtx m;  // model matrix.
        Mtx mv; // modelview matrix.

        guMtxIdentity (m);
        guMtxTransApply (m, m, 0, 0, -100);
        guMtxConcat (v, m, mv);

        GX_LoadPosMtxImm (mv, GX_PNMTX0);
        GX_Begin (GX_QUADS, GX_VTXFMT0, 4);
        draw_vert (0, 0, 0.0, 0.0);
        draw_vert (1, 0, 1.0, 0.0);
        draw_vert (2, 0, 1.0, 1.0);
        draw_vert (3, 0, 0.0, 1.0);
        GX_End ();
}

void GRRLIB_Start(){
	u16 width=640;
	u16 height=480;
	s16 haspect=80;
	s16 vaspect=60;
	
        Mtx p;

        /*** Set new aspect ***/
        square[0] = square[9] = -haspect;
        square[3] = square[6] = haspect;
        square[1] = square[4] = vaspect;
        square[7] = square[10] = -vaspect;

        texturesize = (width * height) * 2;
        texturemem = (u8 *) memalign (32, texturesize);

        GXColor gxbackground = { 0, 0, 0, 0xff };

        memset (gp_fifo, 0, DEFAULT_FIFO_SIZE);

        GX_Init (gp_fifo, DEFAULT_FIFO_SIZE);
        GX_SetCopyClear (gxbackground, 0x00ffffff);

        GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
        GX_SetDispCopyYScale ((f32) vmode->xfbHeight / (f32) vmode->efbHeight);
        GX_SetScissor (0, 0, vmode->fbWidth, vmode->efbHeight);
        GX_SetDispCopySrc (0, 0, vmode->fbWidth, vmode->efbHeight);
        GX_SetDispCopyDst (vmode->fbWidth, vmode->xfbHeight);
        GX_SetCopyFilter (vmode->aa, vmode->sample_pattern, GX_TRUE, vmode->vfilter);
        GX_SetFieldMode (vmode->field_rendering, ((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
        GX_SetPixelFmt (GX_PF_RGB8_Z24, GX_ZC_LINEAR);
        GX_SetCullMode (GX_CULL_NONE);
        GX_CopyDisp (xfb[whichfb ^ 1], GX_TRUE);
        GX_SetDispCopyGamma (GX_GM_1_0);

        guPerspective (p, 60, 1.33f, 10.0f, 1000.0f);
        GX_LoadProjectionMtx (p, GX_PERSPECTIVE);
        memset (texturemem, 0, texturesize);

        vwidth = vheight = -1;
}

void GRRLIB_Render () {
	u16 width=640;
	u16 height=480;
	u8 *buffer=(u8*)GRRLIB_buffer;
	u16 pitch= 640*2;
        u16 h, w;
        u64 *dst = (u64 *) texturemem;
        u64 *src1 = (u64 *) buffer;
        u64 *src2 = (u64 *) (buffer + pitch);
        u64 *src3 = (u64 *) (buffer + (pitch * 2));
        u64 *src4 = (u64 *) (buffer + (pitch * 3));
        u16 rowpitch = (pitch >> 3) * 3 + pitch % 8;

        vwidth = width;
        vheight = height;

        whichfb ^= 1;

        if ((oldvheight != vheight) || (oldvwidth != vwidth)) {
                /** Update scaling **/
                oldvwidth = vwidth;
                oldvheight = vheight;
                draw_init ();
                memset (&view, 0, sizeof(Mtx));
                guLookAt (view, &cam.pos, &cam.up, &cam.view);
                GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
        }

        GX_InvVtxCache ();
        GX_InvalidateTexAll ();
        GX_SetTevOp (GX_TEVSTAGE0, GX_DECAL);
        GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);

        for (h = 0; h < vheight; h += 4) {
                for (w = 0; w < (vwidth >> 2); w++) {
                        *dst++ = *src1++;
                        *dst++ = *src2++;
                        *dst++ = *src3++;
                        *dst++ = *src4++;
                }

                src1 += rowpitch;
                src2 += rowpitch;
                src3 += rowpitch;
                src4 += rowpitch;
        }

        DCFlushRange (texturemem, texturesize);

        GX_SetNumChans (1);
        GX_LoadTexObj (&texobj, GX_TEXMAP0);

        draw_square (view);

        GX_DrawDone ();

        GX_SetZMode (GX_TRUE, GX_LEQUAL, GX_TRUE);
        GX_SetColorUpdate (GX_TRUE);
        GX_CopyDisp (xfb[whichfb], GX_TRUE);
        GX_Flush ();

        VIDEO_SetNextFramebuffer (xfb[whichfb]);
        VIDEO_Flush ();
}

