//#define DEBUG_TILE

/*
 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
 *
 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
 *                           Jerremy Koot (jkoot@snes9x.com)
 *
 * Super FX C emulator code 
 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
 *                           Gary Henderson.
 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
 *
 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
 * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
 * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
 *
 * DOS port code contains the works of other authors. See headers in
 * individual files.
 *
 * Snes9x homepage: http://www.snes9x.com
 *
 * Permission to use, copy, modify and distribute Snes9x in both binary and
 * source form, for non-commercial purposes, is hereby granted without fee,
 * providing that this license information and copyright notice appear with
 * all copies and any derived work.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event shall the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Snes9x is freeware for PERSONAL USE only. Commercial users should
 * seek permission of the copyright holders first. Commercial use includes
 * charging money for Snes9x or software derived from Snes9x.
 *
 * The copyright holders request that bug fixes and improvements to the code
 * should be forwarded to them so everyone can benefit from the modifications
 * in future versions.
 *
 * Super NES and Super Nintendo Entertainment System are trademarks of
 * Nintendo Co., Limited and its subsidiary companies.
 */
#include "snes9x.h"

#include "memmap.h"
#include "ppu.h"
#include "display.h"
#include "gfx.h"
#include "tile_psp.h"

extern s32 realZ1,realZ2;
extern int render_timestamp;

extern int hires_offset,hires_offsetV;
extern int hires_offset2,hires_offsetV2;

tile_cache_t tile_cache_data[3][TILE_CACHE_SIZE];
tile_cache_t *tile_cache_ptr[3][TILE_HASH_SIZE];
//u32 tile_cached_line[3][TILE_HASH_SIZE];
tile_cache_t *tile_cache_first_free[3];
u32 tile_cached[3],tile_resetask;
u32 tile_cache_reset;
u8 *tile_texture[3];  
//multiple textures, one for each tile colour mode => 2bits/pix, 4bits, 8bits
//each one is 512x512 => 64x64 tiles = 4096 tiles/texture


extern struct Vertex *vertices[3];
extern struct Vertex *vertices_ptr[3];
extern struct Vertex *vertices_end[3];
extern struct VertexCol *_verticesCol;
extern struct VertexCol *_verticesCol_ptr;
extern struct VertexCol *_verticesCol_end;
extern int current_bitshift;



// ask for a reset at next rendering pass


void tile_askforreset(s32 addr){	
	if (tile_cache_reset) return;
	if (addr==-1)	{tile_cache_reset=1;	return;}
	tile_resetask++;
	if (tile_resetask==TILE_CACHE_RESET_ASK_MAX) {tile_cache_reset=1;	return;}
	
	
	//invalidate entries
	u32 key=(addr>>4)&TILE_HASH_MASK;
	tile_cache_t *q,*plast,*p=tile_cache_ptr[TILE_2BIT][key];
	if (p){
		
		//tile_cached[TILE_2BIT]-=tile_cached_line[TILE_2BIT][key];
		plast=q=p;		
		while (q) {
			tile_cached[TILE_2BIT]--;
			plast=q;
			q=q->next;
		}
		
		//tile_cached_line[TILE_2BIT][key]=0;
		plast->next=tile_cache_first_free[TILE_2BIT];		
		tile_cache_first_free[TILE_2BIT]=p;
		tile_cache_ptr[TILE_2BIT][key]=NULL;
	}
	key=(addr>>5)&TILE_HASH_MASK;
	p=tile_cache_ptr[TILE_4BIT][key];
	if (p){
		
		//tile_cached[TILE_4BIT]-=tile_cached_line[TILE_4BIT][key];
		plast=q=p;
		while (q) {
			tile_cached[TILE_4BIT]--;
			plast=q;
			q=q->next;
		}
		
		//tile_cached_line[TILE_4BIT][key]=0;
		plast->next=tile_cache_first_free[TILE_4BIT];
		tile_cache_first_free[TILE_4BIT]=p;
		tile_cache_ptr[TILE_4BIT][key]=NULL;
	}
	key=(addr>>6)&TILE_HASH_MASK;
	p=tile_cache_ptr[TILE_8BIT][key];
	if (p){
		//tile_cached[TILE_8BIT]-=tile_cached_line[TILE_8BIT][key];
		plast=q=p;
		while (q) {
			tile_cached[TILE_8BIT]--;
			plast=q;
			q=q->next;
		}
		
		//tile_cached_line[TILE_8BIT][key]=0;
		plast->next=tile_cache_first_free[TILE_8BIT];
		tile_cache_first_free[TILE_8BIT]=p;
		tile_cache_ptr[TILE_8BIT][key]=NULL;
	}	
}
// get tile with hashkey=key
// return texture index if found, 0 if not
INLINE tile_cache_t *tile_get_cache(int cache_num,int key){
	 tile_cache_t *p=tile_cache_ptr[cache_num][key&TILE_HASH_MASK];
	 for (;;){	 	
	 	if (!p) return NULL;
	 	if (p->key==key) {
	 		p->used=render_timestamp;
	 		return p;
	 	}
	 	p=p->next;
	 }	 
}
// insert a new tile in cache
INLINE tile_cache_t *tile_insert_cache(int cache_num,u32 key){	
	tile_cache_t *p=tile_cache_ptr[cache_num][key&TILE_HASH_MASK];
	tile_cache_t *q;
	//get first free cache entry
	q=tile_cache_first_free[cache_num];		
	if (!q) {//error cache full		
		//debug_log("**tile cache full!");
		return NULL; 
	}
	tile_cached[cache_num]++;
	//tile_cached_line[cache_num][key]++;
	//update first free
	tile_cache_first_free[cache_num]=tile_cache_first_free[cache_num]->next;	
	//update new cached tile data
	q->next=NULL;
	q->key=key;
	q->used=render_timestamp;				
	if (!p) {//insert first	
		tile_cache_ptr[cache_num][key&TILE_HASH_MASK]=q;		
	}else{//insert at end
		for (;;){
			if (p->next) p=p->next;
			else {p->next=q;break;}
		}
	}
	return q;	
}
// clean used cached tile & recount total
void tile_clean_cache(int cache_num,int delay){
	int i;
	tile_cache_t *p,*prev_p;
	int nosupp,tosupp;
		
/*char str[64];		
sprintf(str,"ts : %d",render_timestamp);
pgPrintAllBG(34,32,31<<5,str);*/
	//debug_log("cache clean");
	
	nosupp=0;
	tosupp=0;
	for (i=0;i<TILE_HASH_SIZE;i++){
		prev_p=NULL;		
		p=tile_cache_ptr[cache_num][i];
		while (p) {			
			if ((render_timestamp-p->used)>delay) {
				//delete entry				
				tosupp++;
				tile_cached[cache_num]--;
//				tile_cached_line[cache_num][i]--;
				if (!prev_p) {//free tile in first pos				
					tile_cache_ptr[cache_num][i]=p->next;				
					p->next=tile_cache_first_free[cache_num];
					tile_cache_first_free[cache_num]=p;
					p=tile_cache_ptr[cache_num][i];					
				}else{//free tile at n-th pos
					prev_p->next=p->next;
					p->next=tile_cache_first_free[cache_num];
					tile_cache_first_free[cache_num]=p;
					p=prev_p->next;					
				}
			} else {
				prev_p=p;
				p=p->next;
				nosupp++;
			}
		}
	}
/*sprintf(str,"ts : %d, %d %d %d",render_timestamp,nosupp,tosupp,tile_cached[cache_num]);
pgPrintAllBG(34,31,31<<5,str);	
	{  char str[64];			
		sprintf(str,"aft:%d",tile_cached[cache_num]);
		debug_log(str);	
	}*/
}

// reset tile cache
extern "C" {
void tile_reset_cache(){
	int i,num;
	for (num=0;num<3;num++) {
		for (i=0;i<TILE_CACHE_SIZE-1;i++){				
			tile_cache_data[num][i].next=&tile_cache_data[num][i+1];
		}		
		tile_cache_data[num][i].next=NULL;
		tile_cache_first_free[num]=&tile_cache_data[num][0];
				
		tile_cached[num]=0;
		
		for (i=0;i<TILE_HASH_SIZE;i++) tile_cache_ptr[num][i]=NULL;		
	}
	//memset(tile_cache_ptr,0,3*4*TILE_HASH_SIZE);
	//memset(tile_cached_line,0,3*4*TILE_HASH_SIZE);
	
	tile_resetask=0;
	tile_cache_reset=0;
	debug_log("resetcache");
}

void tile_init_cache(){
	//init cache	
	int i,num;
	for (num=0;num<3;num++) {
		for (i=0;i<TILE_CACHE_SIZE-1;i++){		
			tile_cache_data[num][i].text_idx=i;
			tile_cache_data[num][i].next=&tile_cache_data[num][i+1];
		}	
		tile_cache_data[num][i].text_idx=i;
		tile_cache_data[num][i].next=NULL;
		tile_cache_first_free[num]=&tile_cache_data[num][0];
		
		tile_cached[num]=0;
		for (i=0;i<TILE_HASH_SIZE;i++) tile_cache_ptr[num][i]=NULL;		
	}
	//memset(tile_cache_ptr,0,3*4*TILE_HASH_SIZE);
	//memset(tile_cached_line,0,3*4*TILE_HASH_SIZE);
	tile_resetask=0;
	tile_cache_reset=0;
}
}


uint8 pspConvertTile (uint8 *pCache, uint32 TileAddr,uint32 col)
{
    register uint8 *tp = &VRAM[TileAddr];
    uint32 *p = (uint32 *) pCache;
    uint32 non_zero = 0;
    uint8 line;
    uint32 colTmp;
    
    col=(col<<24)|(col<<16)|(col<<8)|col;

    switch (BG.BitShift)
    {
    case 8:
	for (line = 8; line != 0; line--, tp += 2)
	{
	    uint32 p1 = 0;
	    uint32 p2 = 0;
	    register uint8 pix;

	    if ((pix = *(tp + 0)))
	    {
		p1 |= odd_high[0][pix >> 4];
		p2 |= odd_low[0][pix & 0xf];
	    }
	    if ((pix = *(tp + 1)))
	    {
		p1 |= even_high[0][pix >> 4];
		p2 |= even_low[0][pix & 0xf];
	    }
	    if ((pix = *(tp + 16)))
	    {
		p1 |= odd_high[1][pix >> 4];
		p2 |= odd_low[1][pix & 0xf];
	    }
	    if ((pix = *(tp + 17)))
	    {
		p1 |= even_high[1][pix >> 4];
		p2 |= even_low[1][pix & 0xf];
	    }
	    if ((pix = *(tp + 32)))
	    {
		p1 |= odd_high[2][pix >> 4];
		p2 |= odd_low[2][pix & 0xf];
	    }
	    if ((pix = *(tp + 33)))
	    {
		p1 |= even_high[2][pix >> 4];
		p2 |= even_low[2][pix & 0xf];
	    }
	    if ((pix = *(tp + 48)))
	    {
		p1 |= odd_high[3][pix >> 4];
		p2 |= odd_low[3][pix & 0xf];
	    }
	    if ((pix = *(tp + 49)))
	    {
		p1 |= even_high[3][pix >> 4];
		p2 |= even_low[3][pix & 0xf];
	    }
	    p[0] = p1;//|col;
	    p[1] = p2;//|col;
	    p+=512/4;
	    non_zero |= p1 | p2;
	}
	break;

    case 4:
	for (line = 8; line != 0; line--, tp += 2)
	{
	    uint32 p1 = 0;
	    uint32 p2 = 0;
	    register uint8 pix;
	    if ((pix = *(tp + 0)))
	    {
		p1 |= odd_high[0][pix >> 4];
		p2 |= odd_low[0][pix & 0xf];
	    }
	    if ((pix = *(tp + 1)))
	    {
		p1 |= even_high[0][pix >> 4];
		p2 |= even_low[0][pix & 0xf];
	    }
	    if ((pix = *(tp + 16)))
	    {
		p1 |= odd_high[1][pix >> 4];
		p2 |= odd_low[1][pix & 0xf];
	    }
	    if ((pix = *(tp + 17)))
	    {
		p1 |= even_high[1][pix >> 4];
		p2 |= even_low[1][pix & 0xf];
	    }
	    non_zero |= p1 | p2;
	    if (non_zero) {
	    	colTmp=col;
	    	if (!(p1&0x000000FF)) colTmp&=~0x000000FF;
	    	if (!(p1&0x0000FF00)) colTmp&=~0x0000FF00;
	    	if (!(p1&0x00FF0000)) colTmp&=~0x00FF0000;
	    	if (!(p1&0xFF000000)) colTmp&=~0xFF000000;	    	
	    	p[0] = p1|colTmp;
	    	colTmp=col;
	    	if (!(p2&0x000000FF)) colTmp&=~0x000000FF;
	    	if (!(p2&0x0000FF00)) colTmp&=~0x0000FF00;
	    	if (!(p2&0x00FF0000)) colTmp&=~0x00FF0000;
	    	if (!(p2&0xFF000000)) colTmp&=~0xFF000000;	    	
	    	p[1] = p2|colTmp;
	    } else {
	    	p[0] = p[1] = 0;
	    }
	    p+=512/4;
	    
	}
	break;

    case 2:
	for (line = 8; line != 0; line--, tp += 2)
	{
	    uint32 p1 = 0;
	    uint32 p2 = 0;
	    register uint8 pix;
	    if ((pix = *(tp + 0)))
	    {
		p1 |= odd_high[0][pix >> 4];
		p2 |= odd_low[0][pix & 0xf];
	    }
	    if ((pix = *(tp + 1)))
	    {
		p1 |= even_high[0][pix >> 4];
		p2 |= even_low[0][pix & 0xf];
	    }
	    non_zero |= p1 | p2;
	    if (non_zero) {
	    	colTmp=col;
	    	if (!(p1&0x000000FF)) colTmp&=~0x000000FF;
	    	if (!(p1&0x0000FF00)) colTmp&=~0x0000FF00;
	    	if (!(p1&0x00FF0000)) colTmp&=~0x00FF0000;
	    	if (!(p1&0xFF000000)) colTmp&=~0xFF000000;	    	
	    	p[0] = p1|colTmp;
	    	colTmp=col;
	    	if (!(p2&0x000000FF)) colTmp&=~0x000000FF;
	    	if (!(p2&0x0000FF00)) colTmp&=~0x0000FF00;
	    	if (!(p2&0x00FF0000)) colTmp&=~0x00FF0000;
	    	if (!(p2&0xFF000000)) colTmp&=~0xFF000000;	    	
	    	p[1] = p2|colTmp;
	    } else {
	    	p[0] = p[1] = 0;
	    }
	    p+=512/4;
	    non_zero |= p1 | p2;
	}
	break;
    }
    return (non_zero ? TRUE : BLANK_TILE);
}


void pspDrawTile16 (uint32 Tile, s32 x,s32 y, uint32 StartLine,uint32 LineCount) {		
	uint32 u,v,col,TileKey,TileNumber,TileAddr;		
	tile_cache_t *cache_ptr;
  uint8 *pCache;
  
  TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift);
  if (Tile & 0x100) TileAddr += BG.NameSelect; 
  TileAddr &= 0xffff; 
  TileNumber = (TileAddr >> BG.TileShift);
    
  if (BG.DirectColourMode) col=0;     
  else col = (((Tile >> 10) & BG.PaletteMask) << BG.PaletteShift) + BG.StartPalette;
    
  TileKey=TileNumber|(col<<14)|(current_bitshift<<12); //TileNumber is TileAddr(16) >> TileShift(min 4) => max 12bits

  cache_ptr=tile_get_cache(current_bitshift,TileKey);
  if (!cache_ptr) {//tile not cached
  	if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {  	
  		tile_clean_cache(current_bitshift,0);
  		if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {debug_log("cache full!!!");return;}  			
  	}

  	cache_ptr=tile_insert_cache(current_bitshift,TileKey);
  	  	
  	u=(cache_ptr->text_idx&63)<<3;
  	v=(cache_ptr->text_idx>>6)<<3;
   	pCache = tile_texture[current_bitshift]+(v<<9)+u;
   	if ((cache_ptr->tile_type=pspConvertTile ((u8*)NO_CPU_CACHE(pCache), TileAddr,col)==BLANK_TILE)) return;
   	
  }else{
    if (cache_ptr->tile_type==BLANK_TILE) return;
    u=(cache_ptr->text_idx&63)<<3;
		v=(cache_ptr->text_idx>>6)<<3;
  }
  
  if (vertices_ptr[current_bitshift]==vertices_end[current_bitshift]){
  	debug_log("!!ran out of vertices !!");
  	return;
  }

	
	vertices_ptr[current_bitshift][0].x = x; vertices_ptr[current_bitshift][0].y = y/*-StartLine*/; vertices_ptr[current_bitshift][0].z = realZ2;		
	vertices_ptr[current_bitshift][1].x = x+8; vertices_ptr[current_bitshift][1].y = y+LineCount/*-StartLine+8*/; vertices_ptr[current_bitshift][1].z = realZ2;				
	if (!(Tile & (V_FLIP | H_FLIP))) {//NO FLIP
		vertices_ptr[current_bitshift][0].u = u; vertices_ptr[current_bitshift][0].v = v+StartLine;		
		vertices_ptr[current_bitshift][1].u = u+8; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount;		
	}else if (!(Tile & V_FLIP)) {//HFLIP
		vertices_ptr[current_bitshift][1].u = u; vertices_ptr[current_bitshift][0].v = v+StartLine;		
		vertices_ptr[current_bitshift][0].u = u+8; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount;			
	}else if (Tile & H_FLIP) {//HFLIP & VFLIP						
		vertices_ptr[current_bitshift][1].u = u; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount;
		vertices_ptr[current_bitshift][0].u = u+8; vertices_ptr[current_bitshift][0].v = v+8-StartLine;
	}else {//VFLIP
		vertices_ptr[current_bitshift][0].u = u; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount;
		vertices_ptr[current_bitshift][1].u = u+8; vertices_ptr[current_bitshift][0].v = v+8-StartLine;
	}
	vertices_ptr[current_bitshift]+=2;				

}

void pspDrawClippedTile16 (uint32 Tile, s32 x,s32 y,uint32 StartPixel, uint32 Width,uint32 StartLine, uint32 LineCount) {		
#ifdef DEBUG_TILE
return;	
#endif
	uint32 u,v,col,TileKey,TileNumber,TileAddr;		
	tile_cache_t *cache_ptr;
  uint8 *pCache;
  
  TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift);
  if (Tile & 0x100) TileAddr += BG.NameSelect; 
  TileAddr &= 0xffff; 
  TileNumber = (TileAddr >> BG.TileShift);
    
  if (BG.DirectColourMode) col=0;     
  else col = (((Tile >> 10) & BG.PaletteMask) << BG.PaletteShift) + BG.StartPalette;
    
  TileKey=TileNumber|(col<<14)|(current_bitshift<<12); //TileNumber is TileAddr(16) >> TileShift(min 4) => max 12bits
  cache_ptr=tile_get_cache(current_bitshift,TileKey);
  if (!cache_ptr) {//tile not cached
  	if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {
  		tile_clean_cache(current_bitshift,0);  			  		
  		if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {debug_log("cache full!!!");return;}  			
  	}
  	cache_ptr=tile_insert_cache(current_bitshift,TileKey);  	
  	
  	u=(cache_ptr->text_idx&63)<<3;
  	v=(cache_ptr->text_idx>>6)<<3;  	
   	pCache = tile_texture[current_bitshift]+(v<<9)+u;
   	if ((cache_ptr->tile_type=pspConvertTile ((u8*)NO_CPU_CACHE(pCache), TileAddr,col)==BLANK_TILE)) return;   	
  }else{
    if (cache_ptr->tile_type==BLANK_TILE) return;
    u=(cache_ptr->text_idx&63)<<3;
		v=(cache_ptr->text_idx>>6)<<3;  	
  }
  
  if (vertices_ptr[current_bitshift]==vertices_end[current_bitshift]){
  	debug_log("!!ran out of vertices !!");
  	return;
  }
        		
	vertices_ptr[current_bitshift][0].x = x+StartPixel; vertices_ptr[current_bitshift][0].y = y; vertices_ptr[current_bitshift][0].z = realZ2;		
	vertices_ptr[current_bitshift][1].x = x+StartPixel+Width; vertices_ptr[current_bitshift][1].y = y+LineCount; vertices_ptr[current_bitshift][1].z = realZ2;		
				
	if (!(Tile & (V_FLIP | H_FLIP))) {//NO FLIP
		vertices_ptr[current_bitshift][0].u = u+StartPixel; vertices_ptr[current_bitshift][0].v = v+StartLine;
		vertices_ptr[current_bitshift][1].u = u+StartPixel+Width; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount;
	}else if (!(Tile & V_FLIP)) {//HFLIP
		vertices_ptr[current_bitshift][1].u = u+8-StartPixel-Width; vertices_ptr[current_bitshift][0].v = v+StartLine;
		vertices_ptr[current_bitshift][0].u = u+8-StartPixel; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount;
	}
	else if (Tile & H_FLIP) {//HFLIP & VFLIP
		vertices_ptr[current_bitshift][1].u = u+8-StartPixel-Width; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount;
		vertices_ptr[current_bitshift][0].u = u+8-StartPixel; vertices_ptr[current_bitshift][0].v = v+8-StartLine;
	}else {//VFLIP
		vertices_ptr[current_bitshift][0].u = u+StartPixel; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount;
		vertices_ptr[current_bitshift][1].u = u+StartPixel+Width; vertices_ptr[current_bitshift][0].v = v+8-StartLine;
	}				
	vertices_ptr[current_bitshift]+=2;
}


void pspDrawHiResTile16 (uint32 Tile, s32 x,s32 y, uint32 StartLine,uint32 LineCount) {
#ifdef DEBUG_TILE
return;	
#endif
	uint32 u,v,col,TileKey,TileNumber,TileAddr;		
	tile_cache_t *cache_ptr;
  uint8 *pCache;
  
  TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift);
  if (Tile & 0x100) TileAddr += BG.NameSelect; 
  TileAddr &= 0xffff; 
  TileNumber = (TileAddr >> BG.TileShift);
    
  if (BG.DirectColourMode) col=0;     
  else col = (((Tile >> 10) & BG.PaletteMask) << BG.PaletteShift) + BG.StartPalette;
    
  TileKey=TileNumber|(col<<14)|(current_bitshift<<12); //TileNumber is TileAddr(16) >> TileShift(min 4) => max 12bits

  cache_ptr=tile_get_cache(current_bitshift,TileKey);
  if (!cache_ptr) {//tile not cached
  	if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {  	
  		tile_clean_cache(current_bitshift,0);
  		if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {debug_log("cache full!!!");return;}  			
  	}

  	cache_ptr=tile_insert_cache(current_bitshift,TileKey);  	
  	  	
  	u=(cache_ptr->text_idx&63)<<3;
  	v=(cache_ptr->text_idx>>6)<<3;
   	pCache = tile_texture[current_bitshift]+(v<<9)+u;
   	if ((cache_ptr->tile_type=pspConvertTile ((u8*)NO_CPU_CACHE(pCache), TileAddr,col)==BLANK_TILE)) return;
   	
  }else{
    if (cache_ptr->tile_type==BLANK_TILE) return;
    u=(cache_ptr->text_idx&63)<<3;
		v=(cache_ptr->text_idx>>6)<<3;
  }
  
  if (vertices_ptr[current_bitshift]==vertices_end[current_bitshift]){
  	debug_log("!!ran out of vertices !!");
  	return;
  }

	vertices_ptr[current_bitshift][0].x = x; vertices_ptr[current_bitshift][0].y = y; vertices_ptr[current_bitshift][0].z = realZ2;		
	vertices_ptr[current_bitshift][1].x = x+4; vertices_ptr[current_bitshift][1].y = y+LineCount; vertices_ptr[current_bitshift][1].z = realZ2;				
	if (!(Tile & (V_FLIP | H_FLIP))) {//NO FLIP
		vertices_ptr[current_bitshift][0].u = u+hires_offset; vertices_ptr[current_bitshift][0].v = v+StartLine+hires_offsetV;
		vertices_ptr[current_bitshift][1].u = u+8-hires_offset2; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount-hires_offsetV2;
	}else if (!(Tile & V_FLIP)) {//HFLIP
		vertices_ptr[current_bitshift][1].u = u+hires_offset; vertices_ptr[current_bitshift][0].v = v+StartLine+hires_offsetV;
		vertices_ptr[current_bitshift][0].u = u+8-hires_offset2; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount-hires_offsetV2;
	}else if (Tile & H_FLIP) {//HFLIP & VFLIP						
		vertices_ptr[current_bitshift][1].u = u+hires_offset; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount+hires_offsetV;
		vertices_ptr[current_bitshift][0].u = u+8-hires_offset2; vertices_ptr[current_bitshift][0].v = v+8-StartLine-hires_offsetV2;
	}else {//VFLIP
		vertices_ptr[current_bitshift][0].u = u+hires_offset; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount+hires_offsetV;
		vertices_ptr[current_bitshift][1].u = u+8-hires_offset2; vertices_ptr[current_bitshift][0].v = v+8-StartLine-hires_offsetV2;
	}
	vertices_ptr[current_bitshift]+=2;				

}

void pspDrawHiResClippedTile16 (uint32 Tile, s32 x,s32 y,uint32 StartPixel, uint32 Width,uint32 StartLine, uint32 LineCount) {
#ifdef DEBUG_TILE
return;	
#endif
	uint32 u,v,col,TileKey,TileNumber,TileAddr;		
	tile_cache_t *cache_ptr;
  uint8 *pCache;
  
  TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift);
  if (Tile & 0x100) TileAddr += BG.NameSelect; 
  TileAddr &= 0xffff; 
  TileNumber = (TileAddr >> BG.TileShift);
    
  if (BG.DirectColourMode) col=0;     
  else col = (((Tile >> 10) & BG.PaletteMask) << BG.PaletteShift) + BG.StartPalette;
    
  TileKey=TileNumber|(col<<14)|(current_bitshift<<12); //TileNumber is TileAddr(16) >> TileShift(min 4) => max 12bits
  cache_ptr=tile_get_cache(current_bitshift,TileKey);
  if (!cache_ptr) {//tile not cached
  	if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {
  		tile_clean_cache(current_bitshift,0);  			  		
  		if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {debug_log("cache full!!!");return;}  			
  	}
  	cache_ptr=tile_insert_cache(current_bitshift,TileKey);  	
  	
  	u=(cache_ptr->text_idx&63)<<3;
  	v=(cache_ptr->text_idx>>6)<<3;  	
   	pCache = tile_texture[current_bitshift]+(v<<9)+u;
   	if ((cache_ptr->tile_type=pspConvertTile ((u8*)NO_CPU_CACHE(pCache), TileAddr,col)==BLANK_TILE)) return;   	
  }else{
    if (cache_ptr->tile_type==BLANK_TILE) return;
    u=(cache_ptr->text_idx&63)<<3;
		v=(cache_ptr->text_idx>>6)<<3;  	
  }
  
  if (vertices_ptr[current_bitshift]==vertices_end[current_bitshift]){
  	debug_log("!!ran out of vertices !!");
  	return;
  }
        		
	vertices_ptr[current_bitshift][0].x = x+(StartPixel>>1); vertices_ptr[current_bitshift][0].y = y; vertices_ptr[current_bitshift][0].z = realZ2;		
	vertices_ptr[current_bitshift][1].x = x+((StartPixel+Width)>>1); vertices_ptr[current_bitshift][1].y = y+LineCount; vertices_ptr[current_bitshift][1].z = realZ2;
				
	if (!(Tile & (V_FLIP | H_FLIP))) {//NO FLIP
		vertices_ptr[current_bitshift][0].u = u+StartPixel; vertices_ptr[current_bitshift][0].v = v+StartLine;
		vertices_ptr[current_bitshift][1].u = u+StartPixel+Width; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount;
	}else if (!(Tile & V_FLIP)) {//HFLIP
		vertices_ptr[current_bitshift][1].u = u+8-StartPixel-Width; vertices_ptr[current_bitshift][0].v = v+StartLine;
		vertices_ptr[current_bitshift][0].u = u+8-StartPixel; vertices_ptr[current_bitshift][1].v = v+StartLine+LineCount;
	}
	else if (Tile & H_FLIP) {//HFLIP & VFLIP
		vertices_ptr[current_bitshift][1].u = u+8-StartPixel-Width; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount;
		vertices_ptr[current_bitshift][0].u = u+8-StartPixel; vertices_ptr[current_bitshift][0].v = v+8-StartLine;
	}else {//VFLIP
		vertices_ptr[current_bitshift][0].u = u+StartPixel; vertices_ptr[current_bitshift][1].v = v+8-StartLine-LineCount;
		vertices_ptr[current_bitshift][1].u = u+StartPixel+Width; vertices_ptr[current_bitshift][0].v = v+8-StartLine;
	}				
	vertices_ptr[current_bitshift]+=2;
}



void pspDrawLargePixel16 (uint32 Tile, s32 x,s32 y,uint32 StartPixel, uint32 Pixels,uint32 StartLine, uint32 LineCount) {
#ifdef DEBUG_TILE
return;	
#endif
	uint32 u,v,col,TileKey,TileNumber,TileAddr;		
	tile_cache_t *cache_ptr;
  uint8 *pCache;
  
  TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift);
  if (Tile & 0x100) TileAddr += BG.NameSelect; 
  TileAddr &= 0xffff; 
  TileNumber = (TileAddr >> BG.TileShift);
    
  if (BG.DirectColourMode) col=0;     
  else col = (((Tile >> 10) & BG.PaletteMask) << BG.PaletteShift) + BG.StartPalette;
    
  TileKey=TileNumber|(col<<14)|(current_bitshift<<12); //TileNumber is TileAddr(16) >> TileShift(min 4) => max 12bits
  cache_ptr=tile_get_cache(current_bitshift,TileKey);
  if (!cache_ptr) {//tile not cached
  	if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {
  		tile_clean_cache(current_bitshift,0);  			  		
  		if (tile_cached[current_bitshift]==(TILE_CACHE_SIZE-1)) {debug_log("cache full!!!");return;}  			
  	}
  	cache_ptr=tile_insert_cache(current_bitshift,TileKey);  	
  	
  	u=(cache_ptr->text_idx&63)<<3;
  	v=(cache_ptr->text_idx>>6)<<3;  	
   	pCache = tile_texture[current_bitshift]+(v<<9)+u;
   	if ((cache_ptr->tile_type=pspConvertTile ((u8*)NO_CPU_CACHE(pCache), TileAddr,col)==BLANK_TILE)) return;   	
  }else{
    if (cache_ptr->tile_type==BLANK_TILE) return;
    u=(cache_ptr->text_idx&63)<<3;
		v=(cache_ptr->text_idx>>6)<<3;  	
  }
  
  if (_verticesCol_ptr==_verticesCol_end){
  	debug_log("!!ran out of vertices !!");
  	return;
  }
        		
	_verticesCol_ptr[0].x = x; _verticesCol_ptr[0].y = y; _verticesCol_ptr[0].z = realZ2;		
	_verticesCol_ptr[1].x = x+Pixels; _verticesCol_ptr[1].y = y+LineCount; _verticesCol_ptr[1].z = realZ2;
				
	if (!(Tile & (V_FLIP | H_FLIP))) {//NO FLIP
		u+=StartPixel;
		v+=StartLine;		
	}else if (!(Tile & V_FLIP)) {//HFLIP
		u+=7-StartPixel;
		v+=StartLine;
	}else if (Tile & H_FLIP) {//HFLIP & VFLIP
		u+=7-StartPixel;
		v+=7-StartLine;
	}else {//VFLIP
		u+=StartPixel;
		v+=7-StartLine;
	}	
	_verticesCol_ptr[0].u=u;
	_verticesCol_ptr[1].u=u+1;
	_verticesCol_ptr[0].v=v;
	_verticesCol_ptr[1].v=v+1;
	
	//_verticesCol_ptr[0].color=_verticesCol_ptr[1].color=GFX.ScreenColors[tile_texture[current_bitshift][(v<<9)|u]];
	_verticesCol_ptr+=2;
}


