/*
	This simply provides a struct to keep a pointer to a pvr texture and
	its width and height in one variable(appropriately named texture)
	and another one to use for rectangluar areas of a texture(called 
	texture_fragment). Furthermore it provides functions for loading and
	drawing those textures.
*/
#include <png/png.h>
#include <kmg/kmg.h>

namespace kos_gfx
{
	namespace pvr
	{
		struct texture
		{
			pvr_ptr_t tex;
			Uint32 w, h;
		};
		
		struct texture_fragment
		{
			texture tex;
			Uint32 x,y,w,h;
			
			texture_fragment()
			{
				tex.tex=NULL;
				w=1;
				h=1;
			};
			
			texture_fragment(texture t, int tx,int ty,int tw,int th):
			tex(t),x(tx),y(ty),w(tw),h(th)
			{};
		};
		
		//libpngs texture load function does twiddling all the time ;_;;
		texture load_png_texture(std::string filename)
		{
			texture tex;
			
			kos_img_t tmp_img;
			png_to_img(filename.c_str(),PNG_FULL_ALPHA,&tmp_img);
			
			tex.w=tmp_img.w;
			tex.h=tmp_img.h;
			tex.tex=pvr_mem_malloc(tmp_img.w*tmp_img.h*2);
			pvr_txr_load(tmp_img.data,tex.tex,tmp_img.w*tmp_img.h*2);
			//pvr_txr_load_kimg(&tmp_img,tex.tex,PVR_TXRLOAD_16BPP | PVR_TXRLOAD_FMT_NOTWIDDLE);
			
			kos_img_free(&tmp_img,false);
			
			return tex;
		};
		
		texture load_kmg_texture(std::string filename)
		{
			texture tex;
			kos_img_t tmp_img;
			kmg_to_img(filename.c_str(),&tmp_img);
			tex.tex=pvr_mem_malloc(tmp_img.byte_count);
			pvr_txr_load_kimg(&tmp_img,tex.tex,PVR_TXRLOAD_16BPP);
			kos_img_free(&tmp_img,0);
			
			return tex;
		};
		
		void free_texture(texture tex)
		{
			pvr_mem_free(tex.tex);
		};
		
		void free_all_textures()
		{
			pvr_mem_reset();
		};
		
		void draw(texture tex,Uint32 x, Uint32 y, Uint32 w, Uint32 h, Sint32 dest_x, Sint32 dest_y, int scale_w=0, int scale_h=0)
		{
			float real_w=(scale_w==0?w:scale_w), real_h=(scale_h==0?h:scale_h);
			
			float u_min=(x==0?0:((float)x/(float)tex.w));
			float u_max=((float)(x+w)/(float)tex.w);
			float v_min=(y==0?0:((float)y/(float)tex.h));
			float v_max=((float)(y+h)/(float)tex.h);
			
			pvr_poly_hdr_t hdr;
			pvr_poly_cxt_t cxt;
			pvr_vertex_t vertex;
			
			pvr_poly_cxt_txr(&cxt,kos_gfx::pvr::active_list_type,PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED,tex.w,tex.h,tex.tex,PVR_FILTER_NONE);
			pvr_poly_compile(&hdr,&cxt);
			pvr_prim(&hdr,sizeof(hdr));
			
			vertex.flags=PVR_CMD_VERTEX;
			vertex.x=dest_x;
			vertex.y=dest_y;
			vertex.z=kos_gfx::pvr::z_val;
			vertex.u=u_min;
			vertex.v=v_min;
			vertex.argb=PVR_PACK_COLOR(1,1,1,1);
			vertex.oargb=0;
			
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.x+=real_w;
			vertex.u=u_max;
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.y+=real_h;
			vertex.v=v_max;
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.x-=real_w;
			vertex.u=u_min;
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.flags=PVR_CMD_VERTEX_EOL;
			vertex.y-=real_h;
			vertex.v=v_min;
			pvr_prim(&vertex,sizeof(vertex));
			
			++kos_gfx::pvr::z_val;
		};
		
		//with rotation ;-);
		void draw(texture tex,Uint32 x, Uint32 y, Uint32 w, Uint32 h, Sint32 dest_x, Sint32 dest_y, double radians,int scale_w=0, int scale_h=0)
		{
			float real_w=(scale_w==0?w:scale_w), real_h=(scale_h==0?h:scale_h);
			
			float u_min=(x==0?0:((float)x/(float)tex.w));
			float u_max=((float)(x+w)/(float)tex.w);
			float v_min=(y==0?0:((float)y/(float)tex.h));
			float v_max=((float)(y+h)/(float)tex.h);
			
			kos_gfx::math::vector2d<> origin(dest_x+real_w/2,dest_y+real_h/2);
			kos_gfx::math::vector2d<> edge1(dest_x,dest_y), edge2(dest_x+real_w,dest_y), edge3(dest_x+real_w,dest_y+real_h), edge4(dest_x,dest_y+real_h);
			edge1.rotate(radians,origin);
			edge2.rotate(radians,origin);
			edge3.rotate(radians,origin);
			edge4.rotate(radians,origin);
			
			pvr_poly_hdr_t hdr;
			pvr_poly_cxt_t cxt;
			pvr_vertex_t vertex;
			
			pvr_poly_cxt_txr(&cxt,kos_gfx::pvr::active_list_type,PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED,tex.w,tex.h,tex.tex,PVR_FILTER_NONE);
			pvr_poly_compile(&hdr,&cxt);
			pvr_prim(&hdr,sizeof(hdr));
			
			vertex.flags=PVR_CMD_VERTEX;
			vertex.x=edge1.x;
			vertex.y=edge1.y;
			vertex.z=kos_gfx::pvr::z_val;
			vertex.u=u_min;
			vertex.v=v_min;
			vertex.argb=PVR_PACK_COLOR(1,1,1,1);
			vertex.oargb=0;
			
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.x=edge2.x;
			vertex.y=edge2.y;
			vertex.u=u_max;
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.x=edge3.x;
			vertex.y=edge3.y;
			vertex.v=v_max;
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.x=edge4.x;
			vertex.y=edge4.y;
			vertex.u=u_min;
			pvr_prim(&vertex,sizeof(vertex));
			
			vertex.flags=PVR_CMD_VERTEX_EOL;
			vertex.x=edge1.x;
			vertex.y=edge1.y;
			vertex.v=v_min;
			pvr_prim(&vertex,sizeof(vertex));
			
			++kos_gfx::pvr::z_val;
		};
		
		void draw(texture_fragment tex,Sint32 dest_x, Sint32 dest_y, int scale_w=0, int scale_h=0,double radians=0)
		{
			if(tex.tex.tex==NULL)
				return;
				
			if(radians==0)
				draw(tex.tex,tex.x,tex.y,tex.w,tex.h,dest_x,dest_y,scale_w,scale_h);
			else
				draw(tex.tex,tex.x,tex.y,tex.w,tex.h,dest_x,dest_y,radians,scale_w,scale_h);
		};
	};
};
