/*  Copyright 2003-2006 Guillaume Duhamel
    Copyright 2004 Lawrence Sebald
    Copyright 2004-2007 Theo Berkau
 
    This file is part of Yabause.

    Yabause is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Yabause is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Yabause; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#ifdef HAVE_LIBGL

#include "vidogl.h"
#include "vidshared.h"
#include "debug.h"
#include "vdp2.h"
#include "yabause.h"
#include "ygl.h"
#include "yui.h"


#if defined WORDS_BIGENDIAN
#define SAT2YAB1(alpha,temp)      (alpha | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27)
#else
#define SAT2YAB1(alpha,temp)      (alpha << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9)
#endif

#if defined WORDS_BIGENDIAN
#define SAT2YAB2(alpha,dot1,dot2)       ((dot2 & 0xFF << 24) | ((dot2 & 0xFF00) << 8) | ((dot1 & 0xFF) << 8) | alpha)
#else
#define SAT2YAB2(alpha,dot1,dot2)       (alpha << 24 | ((dot1 & 0xFF) << 16) | (dot2 & 0xFF00) | (dot2 & 0xFF))
#endif

#define COLOR_ADDt(b)      (b>0xFF?0xFF:(b<0?0:b))
#define COLOR_ADDb(b1,b2)   COLOR_ADDt((signed) (b1) + (b2))
#ifdef WORDS_BIGENDIAN
#define COLOR_ADD(l,r,g,b)   (COLOR_ADDb((l >> 24) & 0xFF, r) << 24) | \
            (COLOR_ADDb((l >> 16) & 0xFF, g) << 16) | \
            (COLOR_ADDb((l >> 8) & 0xFF, b) << 8) | \
            (l & 0xFF)
#else
#define COLOR_ADD(l,r,g,b)   COLOR_ADDb((l & 0xFF), r) | \
            (COLOR_ADDb((l >> 8 ) & 0xFF, g) << 8) | \
            (COLOR_ADDb((l >> 16 ) & 0xFF, b) << 16) | \
            (l & 0xFF000000)
#endif

int VIDOGLInit(void);
void VIDOGLDeInit(void);
void VIDOGLResize(unsigned int, unsigned int, int);
int VIDOGLIsFullscreen(void);
int VIDOGLVdp1Reset(void);
void VIDOGLVdp1DrawStart(void);
void VIDOGLVdp1DrawEnd(void);
void VIDOGLVdp1NormalSpriteDraw(void);
void VIDOGLVdp1ScaledSpriteDraw(void);
void VIDOGLVdp1DistortedSpriteDraw(void);
void VIDOGLVdp1PolygonDraw(void);
void VIDOGLVdp1PolylineDraw(void);
void VIDOGLVdp1LineDraw(void);
void VIDOGLVdp1UserClipping(void);
void VIDOGLVdp1SystemClipping(void);
void VIDOGLVdp1LocalCoordinate(void);
int VIDOGLVdp2Reset(void);
void VIDOGLVdp2DrawStart(void);
void VIDOGLVdp2DrawEnd(void);
void VIDOGLVdp2DrawScreens(void);
void VIDOGLVdp2SetResolution(u16 TVMD);
void FASTCALL VIDOGLVdp2SetPriorityNBG0(int priority);
void FASTCALL VIDOGLVdp2SetPriorityNBG1(int priority);
void FASTCALL VIDOGLVdp2SetPriorityNBG2(int priority);
void FASTCALL VIDOGLVdp2SetPriorityNBG3(int priority);
void FASTCALL VIDOGLVdp2SetPriorityRBG0(int priority);
void YglGetGlSize(int *width, int *height);

VideoInterface_struct VIDOGL = {
VIDCORE_OGL,
"OpenGL Video Interface",
VIDOGLInit,
VIDOGLDeInit,
VIDOGLResize,
VIDOGLIsFullscreen,
VIDOGLVdp1Reset,
VIDOGLVdp1DrawStart,
VIDOGLVdp1DrawEnd,
VIDOGLVdp1NormalSpriteDraw,
VIDOGLVdp1ScaledSpriteDraw,
VIDOGLVdp1DistortedSpriteDraw,
VIDOGLVdp1PolygonDraw,
VIDOGLVdp1PolylineDraw,
VIDOGLVdp1LineDraw,
VIDOGLVdp1UserClipping,
VIDOGLVdp1SystemClipping,
VIDOGLVdp1LocalCoordinate,
VIDOGLVdp2Reset,
VIDOGLVdp2DrawStart,
VIDOGLVdp2DrawEnd,
VIDOGLVdp2DrawScreens,
VIDOGLVdp2SetResolution,
VIDOGLVdp2SetPriorityNBG0,
VIDOGLVdp2SetPriorityNBG1,
VIDOGLVdp2SetPriorityNBG2,
VIDOGLVdp2SetPriorityNBG3,
VIDOGLVdp2SetPriorityRBG0,
YglOnScreenDebugMessage,
YglGetGlSize
};

float vdp1wratio=1;
float vdp1hratio=1;

int GlWidth=320;
int GlHeight=224;

int vdp1cor=0;
int vdp1cog=0;
int vdp1cob=0;

int vdp2width_gl;
int vdp2height_gl;
static int nbg0priority=0;
static int nbg1priority=0;
static int nbg2priority=0;
static int nbg3priority=0;
static int rbg0priority=0;

static u32 Vdp2ColorRamGetColor(u32 colorindex, int alpha);


// Window Parameter
static vdp2WindowInfo * m_vWindinfo0 = NULL;
static int m_vWindinfo0_size = -1;
static int m_b0WindowChg;
static vdp2WindowInfo * m_vWindinfo1 = NULL;
static int m_vWindinfo1_size = -1;
static int m_b1WindowChg;

static vdp2Lineinfo lineNBG0[512];
static vdp2Lineinfo lineNBG1[512];



// Rotate Screen
static vdp2rotationparameter_struct  paraA;
static vdp2rotationparameter_struct  paraB;



vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2W( vdp2rotationparameter_struct * param, int index );
vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1W( vdp2rotationparameter_struct * param, int index );
vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2Wm3( vdp2rotationparameter_struct * param, int index );
vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1Wm3( vdp2rotationparameter_struct * param, int index );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00NoK( vdp2draw_struct * info, int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00WithK( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01NoK( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01WithK( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02NoK( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKA( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKB( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03NoK( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKA( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKB( vdp2draw_struct * info,int h, int v );
vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithK( vdp2draw_struct * info,int h, int v );


static void FASTCALL Vdp1ReadPriority(vdp1cmd_struct *cmd, int * priority, int * colorcl );
static void FASTCALL Vdp1ReadTexture(vdp1cmd_struct *cmd, YglSprite *sprite, YglTexture *texture);

u32 FASTCALL Vdp2ColorRamGetColorCM01SC0(vdp2draw_struct * info, u32 colorindex, int alpha );
u32 FASTCALL Vdp2ColorRamGetColorCM01SC1(vdp2draw_struct * info, u32 colorindex, int alpha );
u32 FASTCALL Vdp2ColorRamGetColorCM01SC3(vdp2draw_struct * info, u32 colorindex, int alpha );
u32 FASTCALL Vdp2ColorRamGetColorCM2(vdp2draw_struct * info, u32 colorindex, int alpha );


//////////////////////////////////////////////////////////////////////////////


static void FASTCALL Vdp1ReadTexture(vdp1cmd_struct *cmd, YglSprite *sprite, YglTexture *texture)
{
   int shadow;
   int priority;
   int colorcl;
   
   int ednmode;
   int endcnt = 0;

   u32 charAddr = cmd->CMDSRCA * 8;
   u32 dot;
   u8 SPD = ((cmd->CMDPMOD & 0x40) != 0);
   u8 END = ((cmd->CMDPMOD & 0x80) != 0);
   u8 MSB = ((cmd->CMDPMOD & 0x8000) != 0);
   u32 alpha = 0xFF;
   VDP1LOG("Making new sprite %08X\n", charAddr);
   
   

   if( (cmd->CMDPMOD & 0x20) == 0)
      ednmode = 1;
   else 
      ednmode = 0;
   
   Vdp1ReadPriority(cmd, &priority, &colorcl );

   
   alpha = 0xF8;
   if( ((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01  )
   {
      switch( (Vdp2Regs->SPCTL>>12)&0x03 ) 
      {
      case 0:
         if( priority <= ((Vdp2Regs->SPCTL>>8)&0x07) )
         alpha = 0xF8-((colorcl<<3)&0xF8);      
         break;
      case 1:
         if( priority == ((Vdp2Regs->SPCTL>>8)&0x07) )
         alpha = 0xF8-((colorcl<<3)&0xF8);      
         break;
      case 2:
         if( priority >= ((Vdp2Regs->SPCTL>>8)&0x07) )
         alpha = 0xF8-((colorcl<<3)&0xF8);      
         break;
      case 3:
         //if( priority <= (Vdp2Regs->SPCTL>>8)&0x07 )
      //   alpha = 0xF8-((colorcl<<3)&0xF8);      
         break;
      }
   }

   if( (cmd->CMDPMOD & 0x7)==0x03 || (cmd->CMDPMOD & 0x100) )
   {
      alpha = 0x80;
   }
   
   alpha |= priority;
   
   switch((cmd->CMDPMOD >> 3) & 0x7)
   {
      case 0:
      {
         // 4 bpp Bank mode
         u32 colorBank = cmd->CMDCOLR;
         u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4;
         u16 i;

         for(i = 0;i < sprite->h;i++)
         {
            u16 j;
            j = 0;
            while(j < sprite->w)
            {
               dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF);

               // Pixel 1
               if (((dot >> 4) == 0) && !SPD) *texture->textdata++ = 0x00;
               else if( ((dot >> 4) == 0x0F) && !END ) *texture->textdata++ = 0x00;
               else if( MSB ) *texture->textdata++ = (alpha<<24);
               else *texture->textdata++ = Vdp2ColorRamGetColor(((dot >> 4) | colorBank) + colorOffset, alpha);
               j += 1;

               // Pixel 2
               if (((dot & 0xF) == 0) && !SPD) *texture->textdata++  = 0x00;
               else if( ((dot & 0xF) == 0x0F) && !END ) *texture->textdata++ = 0x00;
               else if( MSB ) *texture->textdata++ = (alpha<<24);
               else *texture->textdata++ = Vdp2ColorRamGetColor(((dot & 0xF) | colorBank) + colorOffset, alpha);
               j += 1;

               charAddr += 1;
            }
            texture->textdata += texture->w;
         }
         break;
      }
      case 1:
      {
         // 4 bpp LUT mode
         u16 temp;
         u32 colorLut = cmd->CMDCOLR * 8;
         u16 i;
         u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4;
         
         for(i = 0;i < sprite->h;i++)
         {
            u16 j;
            j = 0;
            endcnt = 0;
            while(j < sprite->w)
            {
               dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF);

               if( ednmode && endcnt >= 2 )
               {
                  *texture->textdata++ = 0x00;
               }else if (((dot >> 4) == 0) && !SPD)
               {
                  *texture->textdata++ = 0;
               }else if (((dot >> 4) == 0x0F) && !END ) // 6. Commandtable end code
               {
                  *texture->textdata++ = 0x0;
                  endcnt++;
                  
               }else{
                  temp = T1ReadWord(Vdp1Ram, ((dot >> 4) * 2 + colorLut) & 0x7FFFF);
                  if (temp & 0x8000)
                  {
                     if( MSB ) *texture->textdata++ = (alpha<<24);
                     else *texture->textdata++ = SAT2YAB1(alpha, temp);
                  }else if( temp != 0x0000)
                  {
                     Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &temp, &shadow, &priority, &colorcl);
                     if( shadow != 0 ) 
                     {
                        *texture->textdata++ = 0x00;
                     }else{
#ifdef WORDS_BIGENDIAN
                        priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1]&0x7;
                        colorcl =  ((u8 *)&Vdp2Regs->CCRSA)[colorcl^1]&0x1F;
#else
                        priority = ((u8 *)&Vdp2Regs->PRISA)[priority]&0x7;
                        colorcl =  ((u8 *)&Vdp2Regs->CCRSA)[colorcl]&0x1F;
#endif
                        alpha = 0xF8;
                        if( ((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01  )
                        {
                           switch( (Vdp2Regs->SPCTL>>12)&0x03 ) 
                           {
                           case 0:
                              if( priority <= ((Vdp2Regs->SPCTL>>8)&0x07) )
                              alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           case 1:
                              if( priority == ((Vdp2Regs->SPCTL>>8)&0x07) )
                              alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           case 2:
                              if( priority >= ((Vdp2Regs->SPCTL>>8)&0x07) )
                              alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           case 3:
                              //if( priority <= (Vdp2Regs->SPCTL>>8)&0x07 )
                           //   alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           }                     
                        }
                        alpha |= priority;
                        if( MSB ) *texture->textdata++ = (alpha<<24);
                        else *texture->textdata++ = Vdp2ColorRamGetColor(temp+colorOffset, alpha);
                        
                     }
                  }else{
                     *texture->textdata++ = 0x0;
                  }
               }

               j += 1;

               if( ednmode && endcnt >= 2 )
               {
                  *texture->textdata++ = 0x00;
               }else if (((dot & 0xF) == 0) && !SPD)
               {
                  *texture->textdata++ = 0x00;
               }else if (((dot&0x0F) == 0x0F) && !END )
               {
                  *texture->textdata++ = 0x0;
                  endcnt++;
               }else{
                  
                  temp = T1ReadWord(Vdp1Ram, ((dot & 0xF) * 2 + colorLut) & 0x7FFFF);
                  
                  if (temp & 0x8000)
                  {
                     if( MSB ) *texture->textdata++ = (alpha<<24);
                     else *texture->textdata++ = SAT2YAB1(alpha, temp);
                  }else if( temp != 0x0000)
                  {
                     
                     Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &temp, &shadow, &priority, &colorcl);
                     if( shadow != 0 ) 
                     {
                        *texture->textdata++ = 0x00;
                     }else{                     
#ifdef WORDS_BIGENDIAN
                        priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1]&0x7;
                        colorcl =  ((u8 *)&Vdp2Regs->CCRSA)[colorcl^1]&0x1F;
#else
                        priority = ((u8 *)&Vdp2Regs->PRISA)[priority]&0x7;
                        colorcl =  ((u8 *)&Vdp2Regs->CCRSA)[colorcl]&0x1F;
#endif
                        alpha = 0xF8;
                        if( ((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01  )
                        {
                           switch( (Vdp2Regs->SPCTL>>12)&0x03 ) 
                           {
                           case 0:
                              if( priority <= ((Vdp2Regs->SPCTL>>8)&0x07) )
                              alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           case 1:
                              if( priority == ((Vdp2Regs->SPCTL>>8)&0x07) )
                              alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           case 2:
                              if( priority >= ((Vdp2Regs->SPCTL>>8)&0x07) )
                              alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           case 3:
                              //if( priority <= (Vdp2Regs->SPCTL>>8)&0x07 )
                              // alpha = 0xF8-((colorcl<<3)&0xF8);      
                              break;
                           } 
                        }
                        alpha |= priority;
                        if( MSB ) *texture->textdata++ = (alpha<<24);
                        else *texture->textdata++ = Vdp2ColorRamGetColor(temp+colorOffset, alpha);
                     }
                  }else
                     *texture->textdata++ = 0x0;
               }

               j += 1;

               charAddr += 1;
            }
            texture->textdata += texture->w;
         }
         break;
      }
      case 2:
      {
         // 8 bpp(64 color) Bank mode
         u32 colorBank = cmd->CMDCOLR;
         u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4;

         u16 i, j;
         
         for(i = 0;i < sprite->h;i++)
         {
            for(j = 0;j < sprite->w;j++)
            {
               dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x3F;
               charAddr++;

               if ((dot == 0) && !SPD) *texture->textdata++ = 0x00;
               else if( (dot == 0xFF) && !END ) *texture->textdata++ = 0x00;
               else if( MSB ) *texture->textdata++ = (alpha<<24);
               else *texture->textdata++ = Vdp2ColorRamGetColor((dot | colorBank) + colorOffset, alpha);
            }
            texture->textdata += texture->w;
         }
         break;
      }
      case 3:
      {
         // 8 bpp(128 color) Bank mode
         u32 colorBank = cmd->CMDCOLR;
         u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4;
         u16 i, j;
         
         for(i = 0;i < sprite->h;i++)
         {
            for(j = 0;j < sprite->w;j++)
            {
               dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x7F;
               charAddr++;

               if ((dot == 0) && !SPD) *texture->textdata++ = 0x00;
               else if( (dot == 0xFF) && !END ) *texture->textdata++ = 0x00;
               else if( MSB ) *texture->textdata++ = (alpha<<24);
               else *texture->textdata++ = Vdp2ColorRamGetColor((dot | colorBank) + colorOffset, alpha);
            }
            texture->textdata += texture->w;
         }
         break;
      }
      case 4:
      {
         // 8 bpp(256 color) Bank mode
         u32 colorBank = cmd->CMDCOLR;
         u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4;
         u16 i, j;

         for(i = 0;i < sprite->h;i++)
         {
            for(j = 0;j < sprite->w;j++)
            {
               dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF);
               charAddr++;

               if ((dot == 0) && !SPD) *texture->textdata++ = 0x00;
               else if( (dot == 0xFF) && !END ) *texture->textdata++ = 0x0;
               else if( MSB ) *texture->textdata++ = (alpha<<24);
               else *texture->textdata++ = Vdp2ColorRamGetColor((dot | colorBank) + colorOffset, alpha);
            }
            texture->textdata += texture->w;
         }
         break;
      }
      case 5:
      {
         // 16 bpp Bank mode
         u16 i, j;
         for(i = 0;i < sprite->h;i++)
         {
            for(j = 0;j < sprite->w;j++)
            {
               dot = T1ReadWord(Vdp1Ram, charAddr & 0x7FFFF);
               charAddr += 2;

               //if (!(dot & 0x8000) && (Vdp2Regs->SPCTL & 0x20)) printf("mixed mode\n");
               if (!(dot & 0x8000) && !SPD) *texture->textdata++ = 0x00;
               else if( (dot == 0x7FFF) && !END ) *texture->textdata++ = 0x0;
               else if( MSB ) *texture->textdata++ = (alpha<<24);
               else *texture->textdata++ = SAT2YAB1(alpha, dot);
            }
            texture->textdata += texture->w;
         }
         break;
      }
      default:
         VDP1LOG("Unimplemented sprite color mode: %X\n", (cmd->CMDPMOD >> 3) & 0x7);
         break;
   }
}

//////////////////////////////////////////////////////////////////////////////

static void FASTCALL Vdp1ReadPriority(vdp1cmd_struct *cmd, int * priority, int * colorcl )
{
   u8 SPCLMD = Vdp2Regs->SPCTL;
   u8 sprite_register;
   u8 *sprprilist = (u8 *)&Vdp2Regs->PRISA;
   u8 *cclist = (u8 *)&Vdp2Regs->CCRSA;   
   u16 lutPri;
   u16 *reg_src = &cmd->CMDCOLR;
   int not_lut = 1;

   // is the sprite is RGB or LUT (in fact, LUT can use bank color, we just hope it won't...)
   if ((SPCLMD & 0x20) && (cmd->CMDCOLR & 0x8000))
   {
      // RGB data, use register 0
      *priority = Vdp2Regs->PRISA & 0x7;
      return;
   }

   if (((cmd->CMDPMOD >> 3) & 0x7) == 1) {
      u32 charAddr, dot, colorLut;

      *priority = Vdp2Regs->PRISA & 0x7;

      charAddr = cmd->CMDSRCA * 8;
      dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF);
      colorLut = cmd->CMDCOLR * 8;
      lutPri = T1ReadWord(Vdp1Ram, (dot >> 4) * 2 + colorLut);
      if (!(lutPri & 0x8000)) {
         not_lut = 0;
         reg_src = &lutPri;
      } else
         return;
   }

   {
      u8 sprite_type = SPCLMD & 0xF;
      switch(sprite_type)
      {
         case 0:
            sprite_register = (*reg_src & 0xC000) >> 14;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x07)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[(cmd->CMDCOLR>>11)&0x07]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x7FF;
            break;
         case 1:
            sprite_register = (*reg_src & 0xE000) >> 13;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x03)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[(cmd->CMDCOLR>>11)&0x03]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x7FF;
            break;
         case 2:
            sprite_register = (*reg_src >> 14) & 0x1;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x07)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[(cmd->CMDCOLR>>11)&0x07]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x7FF;
            break;
         case 3:
            sprite_register = (*reg_src & 0x6000) >> 13;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x03)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x03)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x7FF;
            break;
         case 4:
            sprite_register = (*reg_src & 0x6000) >> 13;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>10)&0x07)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>10)&0x07)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x3FF;
            break;
         case 5:
            sprite_register = (*reg_src & 0x7000) >> 12;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x01)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>11)&0x01)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x7FF;
            break;
         case 6:
            sprite_register = (*reg_src & 0x7000) >> 12;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>10)&0x03)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>10)&0x03)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x3FF;
            break;
         case 7:
            sprite_register = (*reg_src & 0x7000) >> 12;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>9)&0x07)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>9)&0x07)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x1FF;
            break;
         case 8:
            sprite_register = (*reg_src & 0x80) >> 7;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
#else
            *priority = sprprilist[sprite_register] & 0x7;
#endif
            *colorcl =  cclist[0]&0x1F;
            if (not_lut) cmd->CMDCOLR &= 0x7F;
            break;
         case 9:
            sprite_register = (*reg_src & 0x80) >> 7;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x01)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x01)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x3F;
            break;
         case 10:
            sprite_register = (*reg_src & 0xC0) >> 6;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
#else
            *priority = sprprilist[sprite_register] & 0x7;
#endif
            *colorcl =  cclist[0]&0x1F;
            if (not_lut) cmd->CMDCOLR &= 0x3F;
            break;
         case 11:
            sprite_register = 0;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x03)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x03)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0x3F;
            break;
         case 12:
            sprite_register = (*reg_src & 0x80) >> 7;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
#else
            *priority = sprprilist[sprite_register] & 0x7;
#endif
            *colorcl =  cclist[0]&0x1F;
            if (not_lut) cmd->CMDCOLR &= 0xFF;
            break;
         case 13:
            sprite_register = (*reg_src & 0x80) >> 7;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x01)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x01)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0xFF;
            break;
         case 14:
            sprite_register = (*reg_src & 0xC0) >> 6;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[1]&0x1F;            
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[0]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0xFF;
            break;
         case 15:
            sprite_register = 0;
#ifdef WORDS_BIGENDIAN
            *priority = sprprilist[sprite_register^1] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x03)^1]&0x1F;
#else
            *priority = sprprilist[sprite_register] & 0x7;
            *colorcl =  cclist[((cmd->CMDCOLR>>6)&0x03)]&0x1F;
#endif
            if (not_lut) cmd->CMDCOLR &= 0xFF;
            break;
         default:
            VDP1LOG("sprite type %d not implemented\n", sprite_type);

            // if we don't know what to do with a sprite, we put it on top
            *priority = 7;
            break;
      }
   }
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp1SetTextureRatio(int vdp2widthratio, int vdp2heightratio)
{
   float vdp1w=1;
   float vdp1h=1;

   // may need some tweaking

   // Figure out which vdp1 screen mode to use
   switch (Vdp1Regs->TVMR & 7)
   {
      case 0:
      case 2:
      case 3:
          vdp1w=1;
          break;
      case 1:
          vdp1w=2;
          break;
      default:
          vdp1w=1;
          vdp1h=1;
          break;
   }

   // Is double-interlace enabled?
   if (Vdp1Regs->FBCR & 0x8)
      vdp1h=2;

   vdp1wratio = (float)vdp2widthratio / vdp1w;
   vdp1hratio = (float)vdp2heightratio / vdp1h;
}

//////////////////////////////////////////////////////////////////////////////

static u32 Vdp2ColorRamGetColor(u32 colorindex, int alpha)
{
   switch(Vdp2Internal.ColorMode)
   {
      case 0:
      case 1:
      {
         u32 tmp;
         colorindex <<= 1;
         tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF);
         return SAT2YAB1(alpha, tmp);
      }
      case 2:
      {
         u32 tmp1, tmp2;
         colorindex <<= 2;
         colorindex &= 0xFFF;
         tmp1 = T2ReadWord(Vdp2ColorRam, colorindex);
         tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2);
         return SAT2YAB2(alpha, tmp1, tmp2);
      }
      default: break;
   }

   return 0;
}

u32 FASTCALL Vdp2ColorRamGetColorCM01SC0(vdp2draw_struct * info, u32 colorindex, int alpha )
{
   u32 tmp;
   tmp = T2ReadWord(Vdp2ColorRam, (colorindex<<1) & 0xFFF);
   return SAT2YAB1(alpha,tmp);
}

u32 FASTCALL Vdp2ColorRamGetColorCM01SC1(vdp2draw_struct * info, u32 colorindex, int alpha )
{
   u32 tmp;
   tmp = T2ReadWord(Vdp2ColorRam, (colorindex<<1) & 0xFFF);   
   if( (info->specialcolorfunction & 1) == 0 )
   {
      return SAT2YAB1(0xFF,tmp);
   }
   return SAT2YAB1(alpha,tmp);
}

u32 FASTCALL Vdp2ColorRamGetColorCM01SC3(vdp2draw_struct * info, u32 colorindex, int alpha )
{
   u32 tmp;
   colorindex <<= 1;
   tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF);
   if( ((tmp & 0x8000) == 0) )
   {
      return SAT2YAB1(0xFF,tmp);
   }
   return SAT2YAB1(alpha,tmp);
}

u32 FASTCALL Vdp2ColorRamGetColorCM2(vdp2draw_struct * info, u32 colorindex, int alpha )
{
   u32 tmp1, tmp2;
   colorindex <<= 2;
   colorindex &= 0xFFF;
   tmp1 = T2ReadWord(Vdp2ColorRam, colorindex);
   tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2);
   return SAT2YAB2(alpha, tmp1, tmp2);   
}

static int Vdp2SetGetColor( vdp2draw_struct * info )
{
   switch(Vdp2Internal.ColorMode)
   {
      case 0:
      case 1:
         switch( info->specialcolormode )
         {
         case 0:
            info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0;
            break;
         case 1:
            info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC1;
            break;
         case 2:
            info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0; // Not Supported Yet!
            break;
         case 3:
            info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC3;
            break;
         default:             
            info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0;
            break;
         }
         break;
      case 2:
         info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM2;
         break;
      default: 
         info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0;
         break;
   }   
   return 0;
}

//////////////////////////////////////////////////////////////////////////////
// Window

static void Vdp2GenerateWindowInfo(void)
{
    int i;
    int HShift;
    int v = 0;
    u32 LineWinAddr;

    // Is there BG uses Window0?
    if( (Vdp2Regs->WCTLA & 0X2) || (Vdp2Regs->WCTLA & 0X200) || (Vdp2Regs->WCTLB & 0X2) || (Vdp2Regs->WCTLB & 0X200) ||
        (Vdp2Regs->WCTLC & 0X2) || (Vdp2Regs->WCTLC & 0X200) || (Vdp2Regs->WCTLD & 0X2) || (Vdp2Regs->WCTLD & 0X200) || (Vdp2Regs->RPMD == 0X03) )
    {

        // resize to fit resolusion
        if( m_vWindinfo0_size != vdp2height_gl )
        {
            if(m_vWindinfo0 != NULL) free(m_vWindinfo0);
            m_vWindinfo0 = (vdp2WindowInfo*)malloc(sizeof(vdp2WindowInfo)*(vdp2height_gl+8));

            for( i=0; i<vdp2height_gl; i++ )
            {
               m_vWindinfo0[i].WinShowLine = 1; 
               m_vWindinfo0[i].WinHStart   = 0;
               m_vWindinfo0[i].WinHEnd     = 1024;
            }

            m_vWindinfo0_size = vdp2height_gl;
            m_b0WindowChg = 1;
        }

        HShift = 0;
        if( vdp2width_gl>=640 ) HShift = 0; else HShift = 1;


        // Line Table mode
        if( (Vdp2Regs->LWTA0.part.U & 0x8000) )
        {
            int preHStart = -1;
            int preHEnd = -1;
            
            // start address
            LineWinAddr = (u32)((( (Vdp2Regs->LWTA0.part.U & 0x07) << 15) | (Vdp2Regs->LWTA0.part.L >> 1) ) << 2);
            _Ygl->win0_vertexcnt = 0;
            
            for( v = 0; v < vdp2height_gl; v++ )
            {
                if( v < Vdp2Regs->WPSY0 || v > Vdp2Regs->WPEY0 )
                {
                    if( m_vWindinfo0[v].WinShowLine ) m_b0WindowChg = 1;
                    m_vWindinfo0[v].WinShowLine = 0;

                }else{
                    short HStart = Vdp2RamReadWord(LineWinAddr + (v << 2) );
                    short HEnd   = Vdp2RamReadWord(LineWinAddr + (v << 2) + 2);

                    if( HStart < HEnd )
                    {
                        HStart >>= HShift;
                        HEnd   >>= HShift;

                        if( !( m_vWindinfo0[v].WinHStart == HStart && m_vWindinfo0[v].WinHEnd == HEnd ) )
                        {
                            m_b0WindowChg = 1;
                        }

                        m_vWindinfo0[v].WinHStart = HStart;
                        m_vWindinfo0[v].WinHEnd   = HEnd;
                        m_vWindinfo0[v].WinShowLine = 1;
                        
                        if( v == Vdp2Regs->WPSY0 )
                        {
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+0]= HStart;
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+1]= v;                    
                           _Ygl->win0_vertexcnt++;
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+0]= HEnd;
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+1]= v; 
                           _Ygl->win0_vertexcnt++;
                           
                        }else if( ( HStart != preHStart || HEnd != preHEnd) || v == (Vdp2Regs->WPEY0-1) )
                        {
                           if( (v-1) != _Ygl->win0v[(_Ygl->win0_vertexcnt-1)*2+1] )
                           {
                              _Ygl->win0v[_Ygl->win0_vertexcnt*2+0]= preHStart;
                              _Ygl->win0v[_Ygl->win0_vertexcnt*2+1]= v-1;                    
                              _Ygl->win0_vertexcnt++;
                              _Ygl->win0v[_Ygl->win0_vertexcnt*2+0]= preHEnd;
                              _Ygl->win0v[_Ygl->win0_vertexcnt*2+1]= v-1; 
                              _Ygl->win0_vertexcnt++;                           
                           }
                           
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+0]= HStart;
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+1]= v;                    
                           _Ygl->win0_vertexcnt++;
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+0]= HEnd;
                           _Ygl->win0v[_Ygl->win0_vertexcnt*2+1]= v; 
                           _Ygl->win0_vertexcnt++;                           
                        }
                        
                        preHStart = HStart;
                        preHEnd = HEnd;

                    }else{
                        if( m_vWindinfo0[v].WinShowLine ) m_b0WindowChg = 1;
                        m_vWindinfo0[v].WinHStart = 0;
                        m_vWindinfo0[v].WinHEnd   = 0;
                        m_vWindinfo0[v].WinShowLine = 0;
                        
                    }
                }
            }

        // Parameter Mode
        }else{

            // Check Update
            if( !( m_vWindinfo0[0].WinHStart == (Vdp2Regs->WPSX0>>HShift) && m_vWindinfo0[0].WinHEnd == (Vdp2Regs->WPEX0>>HShift) ) )
            {
                m_b0WindowChg = 1;
            }

            for( v = 0; v < vdp2height_gl; v++ )
            {

                m_vWindinfo0[v].WinHStart = Vdp2Regs->WPSX0 >> HShift;
                m_vWindinfo0[v].WinHEnd   = Vdp2Regs->WPEX0 >> HShift;
                if( v < Vdp2Regs->WPSY0 || v >= Vdp2Regs->WPEY0 )
                {
                    if( m_vWindinfo0[v].WinShowLine ) m_b0WindowChg = 1;
                    m_vWindinfo0[v].WinShowLine = 0;
                }else{
                   if( m_vWindinfo0[v].WinShowLine == 0) m_b0WindowChg = 1;
                    m_vWindinfo0[v].WinShowLine = 1;
                }
            }
            
            _Ygl->win0v[0]= Vdp2Regs->WPSX0 >> HShift;
            _Ygl->win0v[1]= Vdp2Regs->WPSY0;
            _Ygl->win0v[2]= Vdp2Regs->WPEX0 >> HShift;
            _Ygl->win0v[3]= Vdp2Regs->WPSY0;
            _Ygl->win0v[4]= Vdp2Regs->WPSX0 >> HShift;
            _Ygl->win0v[5]= Vdp2Regs->WPEY0;
            _Ygl->win0v[6]= Vdp2Regs->WPEX0 >> HShift;
            _Ygl->win0v[7]= Vdp2Regs->WPEY0;
            _Ygl->win0_vertexcnt = 4;

        }
               
    // there is no Window BG
    }else{
       if( m_vWindinfo0_size != 0 )
       {
          m_b0WindowChg = 1;
       }

       
        if( m_vWindinfo0 != NULL )
        {
            free(m_vWindinfo0);
            m_vWindinfo0 = NULL;
        }
        m_vWindinfo0_size = 0;
        _Ygl->win0_vertexcnt = 0;

    }


    // Is there BG uses Window1?
    if( (Vdp2Regs->WCTLA & 0x8) || (Vdp2Regs->WCTLA & 0x800) || (Vdp2Regs->WCTLB & 0x8) || (Vdp2Regs->WCTLB & 0x800) ||
        (Vdp2Regs->WCTLC & 0x8) || (Vdp2Regs->WCTLC & 0x800) || (Vdp2Regs->WCTLD & 0x8) || (Vdp2Regs->WCTLD & 0x800)  )
    {

        // resize to fit resolution
        if( m_vWindinfo1_size != vdp2height_gl )
        {
            if(m_vWindinfo1 != NULL) free(m_vWindinfo1);
            m_vWindinfo1 = (vdp2WindowInfo*)malloc(sizeof(vdp2WindowInfo)*vdp2height_gl);

            for( i=0; i<vdp2height_gl; i++ )
            {
               m_vWindinfo1[i].WinShowLine = 1; 
               m_vWindinfo1[i].WinHStart   = 0;
               m_vWindinfo1[i].WinHEnd     = 1024;
            }

            m_vWindinfo1_size = vdp2height_gl;
            m_b1WindowChg = 1;
        }

        if( vdp2width_gl>=640 ) HShift = 0; else HShift = 1;


        // LineTable mode
        if( (Vdp2Regs->LWTA1.part.U & 0x8000) )
        {
            int preHStart = -1;
            int preHEnd = -1;
           
            _Ygl->win1_vertexcnt = 0;
            // start address for Window table
            LineWinAddr = (u32)((( (Vdp2Regs->LWTA1.part.U & 0x07) << 15) | (Vdp2Regs->LWTA1.part.L >> 1) ) << 2);
            
            for( v = 0; v < vdp2height_gl; v++ )
            {
                if( v < Vdp2Regs->WPSY1 || v > Vdp2Regs->WPEY1 )
                {
                    if( m_vWindinfo1[v].WinShowLine ) m_b1WindowChg = 1;
                    m_vWindinfo1[v].WinShowLine = 0;
                }else{
                    short HStart = Vdp2RamReadWord(LineWinAddr + (v << 2) );
                    short HEnd   = Vdp2RamReadWord(LineWinAddr + (v << 2) + 2);
                    if( HStart < HEnd )
                    {
                        HStart >>= HShift;
                        HEnd   >>= HShift;

                        if( !( m_vWindinfo1[v].WinHStart == HStart && m_vWindinfo1[v].WinHEnd == HEnd ) )
                        {
                            m_b1WindowChg = 1;
                        }

                        m_vWindinfo1[v].WinHStart = HStart;
                        m_vWindinfo1[v].WinHEnd   = HEnd;
                        m_vWindinfo1[v].WinShowLine = 1;

                    }else{
                        if( m_vWindinfo1[v].WinShowLine ) m_b1WindowChg = 1;
                        m_vWindinfo1[v].WinShowLine = 0;
                    }

                        if( v == Vdp2Regs->WPSY1  )
                        {
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HStart;
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v;                    
                           _Ygl->win1_vertexcnt++;
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HEnd;
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v; 
                           _Ygl->win1_vertexcnt++;
                           
                        }else if( ( HStart != preHStart || HEnd != preHEnd) || v == (Vdp2Regs->WPEY1-1) )
                        {
                           if( (v-1) != _Ygl->win1v[(_Ygl->win1_vertexcnt-1)*2+1] )
                           {
                              _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= preHStart;
                              _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v-1;                    
                              _Ygl->win1_vertexcnt++;
                              _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= preHEnd;
                              _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v-1; 
                              _Ygl->win1_vertexcnt++;                           
                           }
                           
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HStart;
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v;                    
                           _Ygl->win1_vertexcnt++;
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HEnd;
                           _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v; 
                           _Ygl->win1_vertexcnt++;                           
                        }
                        
                        preHStart = HStart;
                        preHEnd = HEnd;
                    
                }
            }

        // parameter mode
        }else{

            // check update
            if( !( m_vWindinfo1[0].WinHStart == (Vdp2Regs->WPSX1>>HShift) && m_vWindinfo1[0].WinHEnd == (Vdp2Regs->WPEX1>>HShift) ) )
            {
                m_b1WindowChg = 1;
            }

            for( v = 0; v < vdp2height_gl; v++ )
            {
                m_vWindinfo1[v].WinHStart = Vdp2Regs->WPSX1 >> HShift;
                m_vWindinfo1[v].WinHEnd   = Vdp2Regs->WPEX1 >> HShift;
                if( v < Vdp2Regs->WPSY1 || v > Vdp2Regs->WPEY1 )
                {
                    if( m_vWindinfo1[v].WinShowLine ) m_b1WindowChg = 1;
                    m_vWindinfo1[v].WinShowLine = 0;
                }else{
                   if( m_vWindinfo1[v].WinShowLine == 0) m_b1WindowChg = 1;
                    m_vWindinfo1[v].WinShowLine = 1;
                }
            }
            
            _Ygl->win1v[0]= Vdp2Regs->WPSX1 >> HShift;
            _Ygl->win1v[1]= Vdp2Regs->WPSY1;
            _Ygl->win1v[2]= Vdp2Regs->WPEX1 >> HShift;
            _Ygl->win1v[3]= Vdp2Regs->WPSY1;
            _Ygl->win1v[4]= Vdp2Regs->WPSX1 >> HShift;
            _Ygl->win1v[5]= Vdp2Regs->WPEY1;
            _Ygl->win1v[6]= Vdp2Regs->WPEX1 >> HShift;
            _Ygl->win1v[7]= Vdp2Regs->WPEY1;
            _Ygl->win1_vertexcnt = 4;            

        }

    // no BG uses Window1
    }else{
       
       if( m_vWindinfo1_size != 0 )
       {
          m_b1WindowChg = 1;
       }

        if( m_vWindinfo1 != NULL )
        {
             free(m_vWindinfo1);
            m_vWindinfo1 = NULL;
        }
        m_vWindinfo1_size = 0;
        _Ygl->win1_vertexcnt = 0;
    }
    
   if( m_b1WindowChg || m_b0WindowChg )
   {
       YglNeedToUpdateWindow();
       m_b0WindowChg = 0;
       m_b1WindowChg = 0;      
   }

}

// 0 .. outside,1 .. inside
static INLINE int Vdp2CheckWindow(vdp2draw_struct *info, int x, int y, int area, vdp2WindowInfo * vWindinfo )
{
   // inside
    if( area == 1 )
    {
        if( vWindinfo[y].WinShowLine == 0  ) return 0;
        if( x > vWindinfo[y].WinHStart && x < vWindinfo[y].WinHEnd )
        {
            return 1;
        }else{
            return 0;
        }
    // outside
    }else{
        if( vWindinfo[y].WinShowLine == 0  ) return 1;
        if( x < vWindinfo[y].WinHStart ) return 1;
        if( x > vWindinfo[y].WinHEnd ) return 1;
        return 0;
    }
    return 0;
}

// 0 .. outside,1 .. inside 
static int FASTCALL Vdp2CheckWindowDot(vdp2draw_struct *info, int x, int y )
{
    if( info->bEnWin0 != 0 &&  info->bEnWin1 == 0 )
    {
        return Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 );
    }else if( info->bEnWin0 == 0 &&  info->bEnWin1 != 0 )
    {
        return Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 );
    }else if( info->bEnWin0 != 0 &&  info->bEnWin1 != 0 )
    {
        if( info->LogicWin == 0 )
        {
            return (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 )&
                    Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ));
        }else{
            return (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 )|
                    Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ));
        }
    }
    return 0;
}

// 0 .. all outsize, 1~3 .. partly inside, 4.. all inside 
static int FASTCALL Vdp2CheckWindowRange(vdp2draw_struct *info, int x, int y, int w, int h )
{
    int rtn=0;
    
    if( info->bEnWin0 != 0 &&  info->bEnWin1 == 0 )
    {
        rtn += Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 );
        rtn += Vdp2CheckWindow(info, x+w, y, info->WindowArea0, m_vWindinfo0 );
        rtn += Vdp2CheckWindow(info, x+w, y+h, info->WindowArea0, m_vWindinfo0 );
        rtn += Vdp2CheckWindow(info, x, y+h, info->WindowArea0, m_vWindinfo0 );
        return rtn;
    }else if( info->bEnWin0 == 0 &&  info->bEnWin1 != 0 )
    {
        rtn += Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 );
        rtn += Vdp2CheckWindow(info, x+w, y, info->WindowArea1, m_vWindinfo1 );
        rtn += Vdp2CheckWindow(info, x+w, y+h, info->WindowArea1, m_vWindinfo1 );
        rtn += Vdp2CheckWindow(info, x, y+h, info->WindowArea1, m_vWindinfo1 );
        return rtn;       
    }else if( info->bEnWin0 != 0 &&  info->bEnWin1 != 0 )
    {
        if( info->LogicWin == 0 )
        {
            rtn += (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 ) & 
                    Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ) );
            rtn += (Vdp2CheckWindow(info, x+w, y, info->WindowArea0, m_vWindinfo0 )& 
                    Vdp2CheckWindow(info, x+w, y, info->WindowArea1, m_vWindinfo1 ) );
            rtn += (Vdp2CheckWindow(info, x+w, y+h, info->WindowArea0, m_vWindinfo0 )& 
                    Vdp2CheckWindow(info, x+w, y+h, info->WindowArea1, m_vWindinfo1 ) );
            rtn += (Vdp2CheckWindow(info, x, y+h, info->WindowArea0, m_vWindinfo0 ) & 
                    Vdp2CheckWindow(info, x, y+h, info->WindowArea1, m_vWindinfo1 ) );
            return rtn;
        }else{
            rtn += (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 ) | 
                    Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ) );
            rtn += (Vdp2CheckWindow(info, x+w, y, info->WindowArea0, m_vWindinfo0 ) | 
                    Vdp2CheckWindow(info, x+w, y, info->WindowArea1, m_vWindinfo1 ) );
            rtn += (Vdp2CheckWindow(info, x+w, y+h, info->WindowArea0, m_vWindinfo0 ) | 
                    Vdp2CheckWindow(info, x+w, y+h, info->WindowArea1, m_vWindinfo1 ) );
            rtn += (Vdp2CheckWindow(info, x, y+h, info->WindowArea0, m_vWindinfo0 ) | 
                    Vdp2CheckWindow(info, x, y+h, info->WindowArea1, m_vWindinfo1 ) );
            return rtn;       
        }  
    }
    return 0;
}

void Vdp2GenLineinfo( vdp2draw_struct *info )
{
   int bound = 0;
   int i;
   u16 val1,val2;
   int index = 0;
   if( info->lineinc == 0 || info->islinescroll == 0 ) return;
   
   if( VDPLINE_SY(info->islinescroll)) bound += 0x04;
   if( VDPLINE_SX(info->islinescroll)) bound += 0x04;
   if( VDPLINE_SZ(info->islinescroll)) bound += 0x04;   
   
   for( i = 0; i < vdp2height_gl; i += info->lineinc )
   {
      index = 0;
      if( VDPLINE_SX(info->islinescroll))
      {
         info->lineinfo[i].LineScrollValH = T1ReadWord(Vdp2Ram, info->linescrolltbl+(i/info->lineinc)*bound);
         if( ( info->lineinfo[i].LineScrollValH & 0x400) ) info->lineinfo[i].LineScrollValH |= 0xF800; else info->lineinfo[i].LineScrollValH &= 0x07FF;
         index += 4;
      }else{
         info->lineinfo[i].LineScrollValH = 0;
      }

      if( VDPLINE_SY(info->islinescroll))
      {
         info->lineinfo[i].LineScrollValV = T1ReadWord(Vdp2Ram, info->linescrolltbl+(i/info->lineinc)*bound+index);
         if( ( info->lineinfo[i].LineScrollValV & 0x400) ) info->lineinfo[i].LineScrollValV |= 0xF800; else info->lineinfo[i].LineScrollValV &= 0x07FF;
         index += 4;
      }else{
         info->lineinfo[i].LineScrollValV = 0;
      }

      if( VDPLINE_SZ(info->islinescroll))
      {
         val1=T1ReadWord(Vdp2Ram, info->linescrolltbl+(i/info->lineinc)*bound+index);
         val2=T1ReadWord(Vdp2Ram, info->linescrolltbl+(i/info->lineinc)*bound+index+2);
         //info->lineinfo[i].CoordinateIncH = (float)( (int)((val1) & 0x07) + (float)( (val2) >> 8) / 255.0f );
         info->lineinfo[i].CoordinateIncH = (((int)((val1) & 0x07)<<8) | (int)( (val2) >> 8));
         index += 4;
      }else{
         info->lineinfo[i].CoordinateIncH = 0x0100;
      }

      
   }
}

static void FASTCALL Vdp2DrawCell(vdp2draw_struct *info, YglTexture *texture)
{
   u32 color;
   int i, j;

   switch(info->colornumber)
   {
      case 0: // 4 BPP
         for(i = 0;i < info->cellh;i++)
         {
            for(j = 0;j < info->cellw;j+=4)
            {
               u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF);

               info->charaddr += 2;
               if (!(dot & 0xF000) && info->transparencyenable) color = 0x00000000;
               else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xF000) >> 12)), info->alpha);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
               if (!(dot & 0xF00) && info->transparencyenable) color = 0x00000000;
               else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xF00) >> 8)), info->alpha);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
               if (!(dot & 0xF0) && info->transparencyenable) color = 0x00000000;
               else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xF0) >> 4)), info->alpha);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
               if (!(dot & 0xF) && info->transparencyenable) color = 0x00000000;
               else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | (dot & 0xF)), info->alpha);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
            }
            texture->textdata += texture->w;
         }
         break;
      case 1: // 8 BPP
         for(i = 0;i < info->cellh;i++)
         {
            for(j = 0;j < info->cellw;j+=2)
            {
               u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF);

               info->charaddr += 2;
               if (!(dot & 0xFF00) && info->transparencyenable) color = 0x00000000;
               else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xFF00) >> 8)), info->alpha);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
               if (!(dot & 0xFF) && info->transparencyenable) color = 0x00000000;
               else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | (dot & 0xFF)), info->alpha);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
            }
            texture->textdata += texture->w;
         }
         break;
    case 2: // 16 BPP(palette)
      for(i = 0;i < info->cellh;i++)
      {
        for(j = 0;j < info->cellw;j++)
        {
          u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF);
          if ((dot == 0) && info->transparencyenable) color = 0x00000000;
          else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + dot, info->alpha);
          info->charaddr += 2;
          *texture->textdata++ = info->PostPixelFetchCalc(info, color);
    }
        texture->textdata += texture->w;
      }
      break;
    case 3: // 16 BPP(RGB)
      if( info->islinescroll ) // Nights Movie
      {
         for(i = 0;i < info->cellh;i++)
         {
            int sh,sv;
            u32 baseaddr;
            vdp2Lineinfo * line;
            baseaddr = (u32)info->charaddr;
            line = &(info->lineinfo[i*info->lineinc]);
            
            if( VDPLINE_SX(info->islinescroll) )
               sh = line->LineScrollValH+info->sh;
            else
               sh = info->sh;
            
            if( VDPLINE_SY(info->islinescroll) )
               sv = line->LineScrollValV;
            else
               sv = i+info->sv;

            sh &= (info->cellw-1);
            sv &= (info->cellh-1);
            if( line->LineScrollValH < sh ) sv-=1; 

            baseaddr += ((sh+ sv * info->cellw)<<1);
            
            for(j = 0;j < info->cellw;j++)
            {
               u16 dot;
               u32 addr;
               if( Vdp2CheckWindowDot(info,j,i)==0 ){ *texture->textdata++=0; continue; }
               addr = baseaddr + (j<<1);
               dot = T1ReadWord(Vdp2Ram, addr & 0x7FFFF);
               if (!(dot & 0x8000) && info->transparencyenable) color = 0x00000000;
               else color = SAT2YAB1(0xFF,dot);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
            }
            texture->textdata += texture->w;
         }
         
      }else{
         for(i = 0;i < info->cellh;i++)
         {
         for(j = 0;j < info->cellw;j++)
         {
            u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF);
            info->charaddr += 2;
            if (!(dot & 0x8000) && info->transparencyenable) color = 0x00000000;
            else color = SAT2YAB1(0xFF, dot);
            *texture->textdata++ = info->PostPixelFetchCalc(info, color);
         }
         texture->textdata += texture->w;
         }
      }
      break;
    case 4: // 32 BPP
      if( info->islinescroll ) // Nights Movie
      {
         for(i = 0;i < info->cellh;i++)
         {
            int sh,sv;
            u32 baseaddr;
            vdp2Lineinfo * line;
         	baseaddr = (u32)info->charaddr;
            line = &(info->lineinfo[i*info->lineinc]);
            
			   if( VDPLINE_SX(info->islinescroll) )
				   sh = line->LineScrollValH+info->sh;
			   else
				   sh = info->sh;
			
			   if( VDPLINE_SY(info->islinescroll) )
				   sv = line->LineScrollValV;
			   else
               sv = i+info->sv;

            sh &= (info->cellw-1);
            sv &= (info->cellh-1);
            if( line->LineScrollValH < sh ) sv-=1; 

            baseaddr += ((sh+ sv * info->cellw)<<2);
            
            for(j = 0;j < info->cellw;j++)
            {
               u16 dot1, dot2;
               u32 addr;
   			   if( Vdp2CheckWindowDot(info,j,i)==0 ){ *texture->textdata++=0; continue; }
	   		   addr = baseaddr + (j<<2);
               dot1 = T1ReadWord(Vdp2Ram, addr & 0x7FFFF);
               dot2 = T1ReadWord(Vdp2Ram, (addr+2) & 0x7FFFF);
               if (!(dot1 & 0x8000) && info->transparencyenable) color = 0x00000000;
               else color = SAT2YAB2(info->alpha, dot1, dot2);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
            }
            texture->textdata += texture->w;
         }
      }else{
         for(i = 0;i < info->cellh;i++)
         {
            for(j = 0;j < info->cellw;j++)
            {
               u16 dot1, dot2;
               dot1 = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF);
               info->charaddr += 2;
               dot2 = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF);
               info->charaddr += 2;
               if (!(dot1 & 0x8000) && info->transparencyenable) color = 0x00000000;
               else color = SAT2YAB2(info->alpha, dot1, dot2);
               *texture->textdata++ = info->PostPixelFetchCalc(info, color);
            }
            texture->textdata += texture->w;
         }
      }
      break;
  }
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawPattern(vdp2draw_struct *info, YglTexture *texture)
{
   u32 cacheaddr = ((u32) (info->alpha >> 3) << 27) | (info->paladdr << 20) | info->charaddr;
   YglCache c;
   YglSprite tile;
   int winmode=0;
   tile.dst = 0;
   tile.uclipmode = 0;
   tile.blendmode = info->blendmode;
    
   tile.w = tile.h = info->patternpixelwh;
   tile.flip = info->flipfunction;

   if (info->specialprimode == 1)
      tile.priority = (info->priority & 0xFFFFFFFE) | info->specialfunction;
   else
      tile.priority = info->priority;
   
 
   tile.vertices[0] = info->x * info->coordincx;
   tile.vertices[1] = info->y * info->coordincy;
   tile.vertices[2] = (info->x + tile.w) * info->coordincx;
   tile.vertices[3] = info->y * info->coordincy;
   tile.vertices[4] = (info->x + tile.w) * info->coordincx;
   tile.vertices[5] = (info->y + tile.h) * info->coordincy;
   tile.vertices[6] = info->x * info->coordincx;
   tile.vertices[7] = (info->y + tile.h) * info->coordincy;
   
   
   // Screen culling
   if( tile.vertices[0] >= vdp2width_gl || tile.vertices[1] >= vdp2height_gl || tile.vertices[2] < 0 || tile.vertices[5] < 0 )
   {   
      info->x += tile.w;
      info->y += tile.h;      
      return;
   }
   
   if( (info->bEnWin0 != 0 || info->bEnWin1 != 0) && info->coordincy == 1.0f )
   {                                                 // coordinate inc is not supported yet.
      winmode=Vdp2CheckWindowRange( info,info->x,info->y,tile.w,tile.h);
      if( winmode == 0 ) // all outside, no need to draw 
      {
         info->x += tile.w;
         info->y += tile.h;
         return;
      }
  
   }
   
   if (1 == YglIsCached(cacheaddr,&c) )
   {
      YglCachedQuad(&tile, &c);
      info->x += tile.w;
      info->y += tile.h;
      return;
   }
   YglQuad(&tile, texture,&c);
   YglCacheAdd(cacheaddr,&c);

   switch(info->patternwh)
   {
      case 1:
         Vdp2DrawCell(info, texture);
         break;
      case 2:
         texture->w += 8;
         Vdp2DrawCell(info, texture);
         texture->textdata -= (texture->w + 8) * 8 - 8;
         Vdp2DrawCell(info, texture);
         texture->textdata -= 8;
         Vdp2DrawCell(info, texture);
         texture->textdata -= (texture->w + 8) * 8 - 8;
         Vdp2DrawCell(info, texture);
         break;
   }
   info->x += tile.w;
   info->y += tile.h;
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2PatternAddr(vdp2draw_struct *info)
{
   switch(info->patterndatasize)
   {
      case 1:
      {
         u16 tmp = T1ReadWord(Vdp2Ram, info->addr);

         info->addr += 2;
         info->specialfunction = (info->supplementdata >> 9) & 0x1;
         info->specialcolorfunction = (info->supplementdata >> 8) & 0x1;

         switch(info->colornumber)
         {
            case 0: // in 16 colors
               info->paladdr = ((tmp & 0xF000) >> 12) | ((info->supplementdata & 0xE0) >> 1);
               break;
            default: // not in 16 colors
               info->paladdr = (tmp & 0x7000) >> 8;
               break;
         }

         switch(info->auxmode)
         {
            case 0:
               info->flipfunction = (tmp & 0xC00) >> 10;

               switch(info->patternwh)
               {
                  case 1:
                     info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10);
                     break;
                  case 2:
                     info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10);
                     break;
               }
               break;
            case 1:
               info->flipfunction = 0;

               switch(info->patternwh)
               {
                  case 1:
                     info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10);
                     break;
                  case 2:
                     info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10);
                     break;
               }
               break;
         }

         break;
      }
      case 2: {
         u16 tmp1 = T1ReadWord(Vdp2Ram, info->addr);
         u16 tmp2 = T1ReadWord(Vdp2Ram, info->addr+2);
         info->addr += 4;
         info->charaddr = tmp2 & 0x7FFF;
         info->flipfunction = (tmp1 & 0xC000) >> 14;
         switch(info->colornumber) {
            case 0:
               info->paladdr = (tmp1 & 0x7F);
               break;
            default:
               info->paladdr = (tmp1 & 0x70);
               break;
         }
         info->specialfunction = (tmp1 & 0x2000) >> 13;
         info->specialcolorfunction = (tmp1 & 0x1000) >> 12;
         break;
      }
   }

   if (!(Vdp2Regs->VRSIZE & 0x8000))
      info->charaddr &= 0x3FFF;

   info->charaddr *= 0x20; // thanks Runik
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawPage(vdp2draw_struct *info, YglTexture *texture)
{
   int X, Y;
   int i, j;

   X = info->x;
   for(i = 0;i < info->pagewh;i++)
   {
      Y = info->y;
      info->x = X;
      for(j = 0;j < info->pagewh;j++)
      {
         info->y = Y;
         if ((info->x >= -info->patternpixelwh) &&
             (info->y >= -info->patternpixelwh) &&
             (info->x <= info->draww) &&
             (info->y <= info->drawh))
         {
            Vdp2PatternAddr(info);
            Vdp2DrawPattern(info, texture);
         }
         else
         {
            info->addr += info->patterndatasize * 2;
            info->x += info->patternpixelwh;
            info->y += info->patternpixelwh;
         }
      }
   }
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawPlane(vdp2draw_struct *info, YglTexture *texture)
{
   int X, Y;
   int i, j;

   X = info->x;
   for(i = 0;i < info->planeh;i++)
   {
      Y = info->y;
      info->x = X;
      for(j = 0;j < info->planew;j++)
      {
         info->y = Y;
         Vdp2DrawPage(info, texture);
      }
   }
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawMap(vdp2draw_struct *info, YglTexture *texture)
{
   int i, j;
   int X, Y;
   int xx,yy;

   X = info->x;

   info->patternpixelwh = 8 * info->patternwh;
   info->draww = (int)((float)vdp2width_gl / info->coordincx);
   info->drawh = (int)((float)vdp2height_gl / info->coordincy);

   i=0;
   yy = info->y*info->coordincy;
   while( yy < vdp2height_gl )
   {
      Y = info->y;
      j=0;
      info->x = X;      
      xx = info->x*info->coordincx;
      while( xx < vdp2width_gl )
      {
         info->y = Y;
         info->PlaneAddr(info, info->mapwh * i + j);
         Vdp2DrawPlane(info, texture);
         j++;
         j &= (info->mapwh-1);
         xx += (info->patternpixelwh*info->pagewh*info->planew) * info->coordincx;
      }
      i++;
      i&=(info->mapwh-1);      
      yy += (info->patternpixelwh*info->pagewh*info->planeh) * info->coordincy;
   }
}

//////////////////////////////////////////////////////////////////////////////

static u32 FASTCALL DoNothing(UNUSED void *info, u32 pixel)
{
   return pixel;
}

//////////////////////////////////////////////////////////////////////////////

static u32 FASTCALL DoColorOffset(void *info, u32 pixel)
{
    return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor,
                     ((vdp2draw_struct *)info)->cog,
                     ((vdp2draw_struct *)info)->cob);
}



//////////////////////////////////////////////////////////////////////////////

static INLINE void ReadVdp2ColorOffset(vdp2draw_struct *info, int mask)
{
   if (Vdp2Regs->CLOFEN & mask)
   {
      // color offset enable
      if (Vdp2Regs->CLOFSL & mask)
      {
         // color offset B
         info->cor = Vdp2Regs->COBR & 0xFF;
         if (Vdp2Regs->COBR & 0x100)
            info->cor |= 0xFFFFFF00;

         info->cog = Vdp2Regs->COBG & 0xFF;
         if (Vdp2Regs->COBG & 0x100)
            info->cog |= 0xFFFFFF00;

         info->cob = Vdp2Regs->COBB & 0xFF;
         if (Vdp2Regs->COBB & 0x100)
            info->cob |= 0xFFFFFF00;
      }
      else
      {
         // color offset A
         info->cor = Vdp2Regs->COAR & 0xFF;
         if (Vdp2Regs->COAR & 0x100)
            info->cor |= 0xFFFFFF00;

         info->cog = Vdp2Regs->COAG & 0xFF;
         if (Vdp2Regs->COAG & 0x100)
            info->cog |= 0xFFFFFF00;

         info->cob = Vdp2Regs->COAB & 0xFF;
         if (Vdp2Regs->COAB & 0x100)
            info->cob |= 0xFFFFFF00;
      }

      info->PostPixelFetchCalc = &DoColorOffset;
   }
   else // color offset disable
      info->PostPixelFetchCalc = &DoNothing;
}

//////////////////////////////////////////////////////////////////////////////

static INLINE u32 Vdp2RotationFetchPixel(vdp2draw_struct *info, int x, int y, int cellw)
{
   u32 dot;

   switch(info->colornumber)
   {
      case 0: // 4 BPP
         dot = T1ReadByte(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) / 2) & 0x7FFFF));
         if (!(x & 0x1)) dot >>= 4;
         if (!(dot & 0xF) && info->transparencyenable) return 0x00000000;
         else return Vdp2ColorRamGetColor(info->coloroffset + ((info->paladdr << 4) | (dot & 0xF)), info->alpha);
      case 1: // 8 BPP
         dot = T1ReadByte(Vdp2Ram, ((info->charaddr + (y * cellw) + x) & 0x7FFFF));
         if (!(dot & 0xFF) && info->transparencyenable) return 0x00000000;
         else return Vdp2ColorRamGetColor(info->coloroffset + ((info->paladdr << 4) | (dot & 0xFF)), info->alpha);
      case 2: // 16 BPP(palette)
         dot = T1ReadWord(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) * 2) & 0x7FFFF));
         if ((dot == 0) && info->transparencyenable) return 0x00000000;
         else return Vdp2ColorRamGetColor(info->coloroffset + dot, info->alpha);
      case 3: // 16 BPP(RGB)
         dot = T1ReadWord(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) * 2) & 0x7FFFF));
         if (!(dot & 0x8000) && info->transparencyenable) return 0x00000000;
         else return SAT2YAB1(0xFF, dot);
      case 4: // 32 BPP
         dot = T1ReadLong(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) * 4) & 0x7FFFF));
         if (!(dot & 0x80000000) && info->transparencyenable) return 0x00000000;
         else return SAT2YAB2(info->alpha, (dot >> 16), dot);
      default:
         return 0;
   }
}

//////////////////////////////////////////////////////////////////////////////
static void FASTCALL Vdp2DrawRotation(vdp2draw_struct *info, vdp2rotationparameter_struct *dmy, YglTexture *texture)
{
   int useb = 0;
   int i, j;
   int x, y;
   int cellw, cellh;
   int pagepixelwh;
   int planepixelwidth;
   int planepixelheight;
   int screenwidth;
   int screenheight;
   int oldcellx=-1, oldcelly=-1;
   u32 color;
   int vres,hres;
   int h;
   int v;
   int pagesize;
   int patternshift;
   u32 LineColorRamAdress;   

   vdp2rotationparameter_struct *parameter;
   if( vdp2height_gl >= 448 ) vres = (vdp2height_gl>>1); else vres = vdp2height_gl;
   if( vdp2width_gl >= 640 ) hres = (vdp2width_gl>>1); else hres = vdp2width_gl;
   info->vertices[0] = 0;
   info->vertices[1] = 0;
   info->vertices[2] = vdp2width_gl;
   info->vertices[3] = 0;
   info->vertices[4] = vdp2width_gl;
   info->vertices[5] = vdp2height_gl;
   info->vertices[6] = 0;
   info->vertices[7] = vdp2height_gl;
   cellw = info->cellw;
   cellh = info->cellh;   
   info->cellw = hres;
   info->cellh = vres;
   info->flipfunction = 0;
   YglQuad((YglSprite *)info, texture,NULL);
   info->cellw = cellw;
   info->cellh = cellh;
   
   if( Vdp2Regs->RPMD != 0 ) useb = 1;
   
   if (!info->isbitmap)
   {
      pagepixelwh=64*8;
      planepixelwidth=info->planew*pagepixelwh;
      planepixelheight=info->planeh*pagepixelwh;
      screenwidth=4*planepixelwidth;
      screenheight=4*planepixelheight;
      oldcellx=-1;
      oldcelly=-1;
      pagesize=info->pagewh*info->pagewh;
      patternshift = (2+info->patternwh);
   }
   else
   {
      pagepixelwh=0;
      planepixelwidth=0;
      planepixelheight=0;
      screenwidth=0;
      screenheight=0;
      oldcellx=0;
      oldcelly=0;
      pagesize=0;
      patternshift = 0;      
   }
   
   if( info->LineColorBase !=0 )
   {
      LineColorRamAdress = (T1ReadWord(Vdp2Ram,info->LineColorBase)&0x780) + info->coloroffset;
   }else{
      LineColorRamAdress = 0x00;
   }
            

    paraA.dx = paraA.A * paraA.deltaX + paraA.B * paraA.deltaY;
    paraA.dy = paraA.D * paraA.deltaX + paraA.E * paraA.deltaY;      
    paraA.Xp = paraA.A * (paraA.Px - paraA.Cx) + 
               paraA.B * (paraA.Py - paraA.Cy) + 
               paraA.C * (paraA.Pz - paraA.Cz) + paraA.Cx + paraA.Mx;
    paraA.Yp = paraA.D * (paraA.Px - paraA.Cx) + 
               paraA.E * (paraA.Py - paraA.Cy) + 
               paraA.F * (paraA.Pz - paraA.Cz) + paraA.Cy + paraA.My;
                
    if(useb)
    {
      paraB.dx = paraB.A * paraB.deltaX + paraB.B * paraB.deltaY;
      paraB.dy = paraB.D * paraB.deltaX + paraB.E * paraB.deltaY;           
      paraB.Xp = paraB.A * (paraB.Px - paraB.Cx) + paraB.B * (paraB.Py - paraB.Cy) 
               + paraB.C * (paraB.Pz - paraB.Cz) + paraB.Cx + paraB.Mx;
      paraB.Yp = paraB.D * (paraB.Px - paraB.Cx) + paraB.E * (paraB.Py - paraB.Cy)
               + paraB.F * (paraB.Pz - paraB.Cz) + paraB.Cy + paraB.My;
    }
    
   
   for (j = 0; j < vres; j++)
   {   
      paraA.Xsp = paraA.A * ((paraA.Xst + paraA.deltaXst * j) - paraA.Px) +
                  paraA.B * ((paraA.Yst + paraA.deltaYst * j) - paraA.Py) +
                  paraA.C * (paraA.Zst - paraA.Pz);
               
      paraA.Ysp = paraA.D * ((paraA.Xst + paraA.deltaXst *j) - paraA.Px) +
                  paraA.E * ((paraA.Yst + paraA.deltaYst * j) - paraA.Py) +
                  paraA.F * (paraA.Zst - paraA.Pz);
               
      paraA.KtablV = paraA.deltaKAst* j;               
      if(useb)
      {
         paraB.Xsp = paraB.A * ((paraB.Xst + paraB.deltaXst * j) - paraB.Px) +
                  paraB.B * ((paraB.Yst + paraB.deltaYst * j) - paraB.Py) +
                  paraB.C * (paraB.Zst - paraB.Pz);
                  
         paraB.Ysp = paraB.D * ((paraB.Xst + paraB.deltaXst * j) - paraB.Px) +
                  paraB.E * ((paraB.Yst + paraB.deltaYst * j) - paraB.Py) +
                  paraB.F * (paraB.Zst - paraB.Pz);
                  
         paraB.KtablV = paraB.deltaKAst * j;   
      }
      

      if( (Vdp2Regs->LCTA.part.U & 0x8000) != 0 && info->LineColorBase !=0 )
      {
         LineColorRamAdress = (T1ReadWord(Vdp2Ram,info->LineColorBase+(y<<1))&0x780) + info->coloroffset;
      }      

      for( i = 0; i < hres; i++ )
      {
         parameter = info->GetRParam(info,i,j);
         if( parameter == NULL )
         {
            *(texture->textdata++) = 0x000000;
            continue;
         }
         
         h = (parameter->ky * ( parameter->Xsp + parameter->dx * i ) + parameter->Xp);
         v = (parameter->ky * ( parameter->Ysp + parameter->dy * i ) + parameter->Yp);

         if (info->isbitmap)
         {
            h &= cellw-1;
            v &= cellh-1;

            // Fetch Pixel
            color = Vdp2RotationFetchPixel(info, h, v, cellw);
         }
         else
         {
             // Tile
            int planenum;
            if( (h < 0 || h >= parameter->MaxH) || (v < 0 || v >= parameter->MaxV) )
            {
               switch( parameter->screenover )
               {
               case OVERMODE_REPEAT:
                  h &= (parameter->MaxH-1);
                  v &= (parameter->MaxH-1);
                  break;
               case OVERMODE_SELPATNAME:
                  *(texture->textdata++) = 0x000000;  // ToDO
                  continue;
                  break;
               default:
                  *(texture->textdata++) = 0x000000;
                  continue;
               }
            }

            x = h;
            y = v;
            

            if ((x>>patternshift) != oldcellx || (y>>patternshift) != oldcelly)
            {
               oldcellx = x>>patternshift;
               oldcelly = y>>patternshift;

               // Calculate which plane we're dealing with
               planenum = (x >> parameter->ShiftPaneX) + ((y >> parameter->ShiftPaneY) << 2);
               x &= parameter->MskH;
               y &= parameter->MskV;                  
               info->addr = parameter->PlaneAddrv[planenum];
                    
                  // Figure out which page it's on(if plane size is not 1x1)
                   info->addr += (((y>>9) * pagesize * info->planew) +
                                ((x>>9) * pagesize) +
                                (((y&511)>>patternshift) * info->pagewh) +
                                ((x&511)>>patternshift)) << info->patterndatasize;

                    Vdp2PatternAddr(info); // Heh, this could be optimized
               }
               
               // Figure out which pixel in the tile we want
               if (info->patternwh == 1)
               {
                  x &= 8-1;
                  y &= 8-1;

                  // vertical flip
                  if (info->flipfunction & 0x2)
                     y = 8 - 1 - y;

                  // horizontal flip
                  if (info->flipfunction & 0x1)
                     x = 8 - 1 - x;
               }
               else
               {
                  if (info->flipfunction)
                  {
                     y &= 16 - 1;
                     if (info->flipfunction & 0x2)
                     {
                        if (!(y & 8))
                           y = 8 - 1 - y + 16;
                        else
                           y = 16 - 1 - y;
                     }
                     else if (y & 8)
                        y += 8;

                     if (info->flipfunction & 0x1)
                     {
                        if (!(x & 8))
                           y += 8;

                        x &= 8-1;
                        x = 8 - 1 - x;
                     }
                     else if (x & 8)
                     {
                        y += 8;
                        x &= 8-1;
                     }
                     else
                        x &= 8-1;
                  }
                  else
                  {
                     y &= 16 - 1;
                     if (y & 8)
                        y += 8;
                     if (x & 8)
                        y += 8;
                     x &= 8-1;
                  }
               }

               // Fetch pixel
               color = Vdp2RotationFetchPixel(info, x, y, 8);
            }

            if( parameter->lineaddr != 0xFFFFFFFF && ((Vdp2Regs->CCCTL>>8)&0x01) )
            {
                  u32 linecolor = Vdp2ColorRamGetColor(LineColorRamAdress|parameter->lineaddr,0xFF);
                  color = COLOR_ADD(color, (linecolor)&0xFF,
                                           (linecolor>>8)&0xFF,
                                           (linecolor>>16)&0xFF);            
            }

            *(texture->textdata++) = info->PostPixelFetchCalc(info, color);
         }

         texture->textdata += texture->w;
   }
}

   


//////////////////////////////////////////////////////////////////////////////

static void SetSaturnResolution(int width, int height)
{
   YglChangeResolution(width, height);

   vdp2width_gl=width;
   vdp2height_gl=height;
}

//////////////////////////////////////////////////////////////////////////////

int VIDOGLInit(void)
{
	GlWidth = 320;
	GlHeight = 224;

   if (YglInit(2048, 1024, 8) != 0)
      return -1;

   SetSaturnResolution(320, 224);

   vdp1wratio = 1;
   vdp1hratio = 1;

   return 0;
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLDeInit(void)
{
   YglDeInit();
}

//////////////////////////////////////////////////////////////////////////////

int _VIDOGLIsFullscreen;

void VIDOGLResize(unsigned int w, unsigned int h, int on)
{
   glDeleteTextures(1, &_Ygl->texture);

   _VIDOGLIsFullscreen = on;

   if (on)
      YuiSetVideoMode(w, h, 32, 1);
   else
      YuiSetVideoMode(w, h, 32, 0);

   GlHeight=h;
   GlWidth=w;
   
   YglGLInit(2048, 1024);
   glViewport(0, 0, w, h);
   YglNeedToUpdateWindow();

   SetSaturnResolution(vdp2width_gl, vdp2height_gl);

}

//////////////////////////////////////////////////////////////////////////////

int VIDOGLIsFullscreen(void) {
   return _VIDOGLIsFullscreen;
}

//////////////////////////////////////////////////////////////////////////////

int VIDOGLVdp1Reset(void)
{
   return 0;
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1DrawStart(void)
{
   int i;
   int maxpri;
   int minpri;
   u8 *sprprilist = (u8 *)&Vdp2Regs->PRISA;
   
   YglCacheReset();
   

   maxpri = 0x00;
   minpri = 0x07;   
   for( i=0; i<8; i++ )
   {
      if( (sprprilist[i]&0x07) < minpri ) minpri = (sprprilist[i]&0x07);
      if( (sprprilist[i]&0x07) > maxpri ) maxpri = (sprprilist[i]&0x07);
   }
   _Ygl->vdp1_maxpri = maxpri;
   _Ygl->vdp1_minpri = minpri;

   if (Vdp2Regs->CLOFEN & 0x40)
   {
      // color offset enable
      if (Vdp2Regs->CLOFSL & 0x40)
      {
         // color offset B
         vdp1cor = Vdp2Regs->COBR & 0xFF;
         if (Vdp2Regs->COBR & 0x100)
            vdp1cor |= 0xFFFFFF00;

         vdp1cog = Vdp2Regs->COBG & 0xFF;
         if (Vdp2Regs->COBG & 0x100)
            vdp1cog |= 0xFFFFFF00;

         vdp1cob = Vdp2Regs->COBB & 0xFF;
         if (Vdp2Regs->COBB & 0x100)
            vdp1cob |= 0xFFFFFF00;
      }
      else
      {
         // color offset A
         vdp1cor = Vdp2Regs->COAR & 0xFF;
         if (Vdp2Regs->COAR & 0x100)
            vdp1cor |= 0xFFFFFF00;

         vdp1cog = Vdp2Regs->COAG & 0xFF;
         if (Vdp2Regs->COAG & 0x100)
            vdp1cog |= 0xFFFFFF00;

         vdp1cob = Vdp2Regs->COAB & 0xFF;
         if (Vdp2Regs->COAB & 0x100)
            vdp1cob |= 0xFFFFFF00;
      }
   }
   else // color offset disable
      vdp1cor = vdp1cog = vdp1cob = 0;
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1DrawEnd(void)
{
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1NormalSpriteDraw(void)
{
   vdp1cmd_struct cmd;
   YglSprite sprite;
   YglTexture texture;
   YglCache cash;
   u32 tmp;
   s16 x, y;
   u16 CMDPMOD;
   u16 color2;
   float col[4*4];
   int i;
   
   
   Vdp1ReadCommand(&cmd, Vdp1Regs->addr);
   sprite.dst=0;
   sprite.blendmode=0;

   x = cmd.CMDXA + Vdp1Regs->localX;
   y = cmd.CMDYA + Vdp1Regs->localY;
   sprite.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8;
   sprite.h = cmd.CMDSIZE & 0xFF;

   sprite.flip = (cmd.CMDCTRL & 0x30) >> 4;

   sprite.vertices[0] = (int)((float)x * vdp1wratio);
   sprite.vertices[1] = (int)((float)y * vdp1hratio);
   sprite.vertices[2] = (int)((float)(x + sprite.w) * vdp1wratio);
   sprite.vertices[3] = (int)((float)y * vdp1hratio);
   sprite.vertices[4] = (int)((float)(x + sprite.w) * vdp1wratio);
   sprite.vertices[5] = (int)((float)(y + sprite.h) * vdp1hratio);
   sprite.vertices[6] = (int)((float)x * vdp1wratio);
   sprite.vertices[7] = (int)((float)(y + sprite.h) * vdp1hratio);

   tmp = cmd.CMDSRCA;
   tmp <<= 16;
   tmp |= cmd.CMDCOLR;

   sprite.priority = 8;

   CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4);
   
   sprite.uclipmode=(CMDPMOD>>9)&0x03;
   
   // Half trans parent to VDP1 Framebuffer
   if( (CMDPMOD & 0x7)==0x03 || (CMDPMOD & 0x100) )
   {
      tmp |= 0x00010000;
      sprite.blendmode = 0x80;
   }
   
   if((CMDPMOD & 0x8000) != 0)
   {
      tmp |= 0x00020000;
   }

   if( (CMDPMOD & 4)  )
   {
      for (i=0; i<4; i++)
      {
         color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1));
         col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f;
         col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f;
         col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f;
         col[(i << 2) + 3] = 1.0f;
      }
     
      if (sprite.w > 0 && sprite.h > 1)
      {
         if (1 == YglIsCached(tmp,&cash) )
         {
            YglCacheQuadGrowShading(&sprite, col,&cash);
            return;
         }

         YglQuadGrowShading(&sprite, &texture,col,&cash);
         YglCacheAdd(tmp,&cash);
         Vdp1ReadTexture(&cmd, &sprite, &texture);
         return;
      }
   
   }
   else // No Gouraud shading, use same color for all 4 vertices
   {
      if (sprite.w > 0 && sprite.h > 1)
      {
         if (1 == YglIsCached(tmp,&cash) )
         {
            YglCachedQuad(&sprite, &cash);
            return;
         }

         YglQuad(&sprite, &texture,&cash);
         YglCacheAdd(tmp,&cash);

         Vdp1ReadTexture(&cmd, &sprite, &texture);
      }
   }
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1ScaledSpriteDraw(void)
{
   vdp1cmd_struct cmd;
   YglSprite sprite;
   YglTexture texture;
   YglCache cash;
   u32 tmp;
   s16 rw=0, rh=0;
   s16 x, y;
   u16 CMDPMOD;
   u16 color2;
   float col[4*4];
   int i;

   Vdp1ReadCommand(&cmd, Vdp1Regs->addr);
   sprite.dst=0;
   sprite.blendmode=0;
   
   x = cmd.CMDXA + Vdp1Regs->localX;
   y = cmd.CMDYA + Vdp1Regs->localY;
   sprite.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8;
   sprite.h = cmd.CMDSIZE & 0xFF;
   sprite.flip = (cmd.CMDCTRL & 0x30) >> 4;

   // Setup Zoom Point
   switch ((cmd.CMDCTRL & 0xF00) >> 8)
   {
      case 0x0: // Only two coordinates
         rw = cmd.CMDXC - x + Vdp1Regs->localX + 1;
         rh = cmd.CMDYC - y + Vdp1Regs->localY + 1;
         break;
      case 0x5: // Upper-left
         rw = cmd.CMDXB + 1;
         rh = cmd.CMDYB + 1;
         break;
      case 0x6: // Upper-Center
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         x = x - rw/2;
         rw++;
         rh++;
         break;
      case 0x7: // Upper-Right
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         x = x - rw;
         rw++;
         rh++;
         break;
      case 0x9: // Center-left
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         y = y - rh/2;
         rw++;
         rh++;
         break;
      case 0xA: // Center-center
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         x = x - rw/2;
         y = y - rh/2;
         rw++;
         rh++;
         break;
      case 0xB: // Center-right
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         x = x - rw;
         y = y - rh/2;
         rw++;
         rh++;
         break;
      case 0xD: // Lower-left
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         y = y - rh;
         rw++;
         rh++;
         break;
      case 0xE: // Lower-center
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         x = x - rw/2;
         y = y - rh;
         rw++;
         rh++;
         break;
      case 0xF: // Lower-right
         rw = cmd.CMDXB;
         rh = cmd.CMDYB;
         x = x - rw;
         y = y - rh;
         rw++;
         rh++;
         break;
      default: break;
   }

   sprite.vertices[0] = (int)((float)x * vdp1wratio);
   sprite.vertices[1] = (int)((float)y * vdp1hratio);
   sprite.vertices[2] = (int)((float)(x + rw) * vdp1wratio);
   sprite.vertices[3] = (int)((float)y * vdp1hratio);
   sprite.vertices[4] = (int)((float)(x + rw) * vdp1wratio);
   sprite.vertices[5] = (int)((float)(y + rh) * vdp1hratio);
   sprite.vertices[6] = (int)((float)x * vdp1wratio);
   sprite.vertices[7] = (int)((float)(y + rh) * vdp1hratio);

   tmp = cmd.CMDSRCA;
   tmp <<= 16;
   tmp |= cmd.CMDCOLR;

   CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4);
   sprite.uclipmode=(CMDPMOD>>9)&0x03;
   
   sprite.priority = 8;
   
   // Half trans parent to VDP1 Framebuffer
   if( (CMDPMOD & 0x7)==0x03 || (CMDPMOD & 0x100) )
   {
      tmp |= 0x00010000;
      sprite.blendmode = 0x80;
   }  
   
   // MSB
   if((CMDPMOD & 0x8000) != 0)
   {
      tmp |= 0x00020000;
   }
   
   
   if ( (CMDPMOD & 4) )
   {
      for (i=0; i<4; i++)
      {
         color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1));
         col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f;
         col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f;
         col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f;
         col[(i << 2) + 3] = 1.0f;
      }
     
      if (sprite.w > 0 && sprite.h > 1)
      {
         if (1 == YglIsCached(tmp,&cash) )
         {
            YglCacheQuadGrowShading(&sprite, col,&cash);
            return;
         }

         YglQuadGrowShading(&sprite, &texture,col,&cash);
         YglCacheAdd(tmp,&cash);
         Vdp1ReadTexture(&cmd, &sprite, &texture);
         return;
      }
   
   }
   else // No Gouraud shading, use same color for all 4 vertices
   {
      if (sprite.w > 0 && sprite.h > 1)
      {
         if (1 == YglIsCached(tmp,&cash) )
         {
            YglCachedQuad(&sprite, &cash);
            return;
         }

         YglQuad(&sprite, &texture,&cash);
         YglCacheAdd(tmp,&cash);

         Vdp1ReadTexture(&cmd, &sprite, &texture);
      }
   }
  
}

//////////////////////////////////////////////////////////////////////////////


void VIDOGLVdp1DistortedSpriteDraw(void)
{
   vdp1cmd_struct cmd;
   YglSprite sprite;
   YglTexture texture;
   YglCache cash;
   u32 tmp;
   u16 CMDPMOD;
   u16 color2;
   int i;
   float col[4*4];
   

   Vdp1ReadCommand(&cmd, Vdp1Regs->addr);
   sprite.blendmode=0;
   sprite.dst = 1;
   sprite.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8;
   sprite.h = cmd.CMDSIZE & 0xFF;

   sprite.flip = (cmd.CMDCTRL & 0x30) >> 4;

   sprite.vertices[0] = (s32)((float)(cmd.CMDXA + Vdp1Regs->localX) * vdp1wratio);
   sprite.vertices[1] = (s32)((float)(cmd.CMDYA + Vdp1Regs->localY) * vdp1hratio);
   sprite.vertices[2] = (s32)((float)((cmd.CMDXB) + Vdp1Regs->localX) * vdp1wratio);
   sprite.vertices[3] = (s32)((float)(cmd.CMDYB + Vdp1Regs->localY) * vdp1hratio);
   sprite.vertices[4] = (s32)((float)((cmd.CMDXC) + Vdp1Regs->localX) * vdp1wratio);
   sprite.vertices[5] = (s32)((float)((cmd.CMDYC) + Vdp1Regs->localY) * vdp1hratio);
   sprite.vertices[6] = (s32)((float)(cmd.CMDXD + Vdp1Regs->localX) * vdp1wratio);
   sprite.vertices[7] = (s32)((float)((cmd.CMDYD) + Vdp1Regs->localY) * vdp1hratio);

   tmp = cmd.CMDSRCA;

   tmp <<= 16;
   tmp |= cmd.CMDCOLR;

   CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4);
   
   sprite.priority = 8;
   
   sprite.uclipmode=(CMDPMOD>>9)&0x03;
   
   // Half trans parent to VDP1 Framebuffer
   if( (CMDPMOD & 0x7)==0x03 || (CMDPMOD & 0x100) )
   {
      tmp |= 0x00010000;
      sprite.blendmode = 0x80;
   }   

   // MSB
   if((CMDPMOD & 0x8000) != 0)
   {
      tmp |= 0x00020000;
   }
   
   // Check if the Gouraud shading bit is set and the color mode is RGB
   if ( (CMDPMOD & 4) )
   {
      for (i=0; i<4; i++)
      {
         color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1));
         col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f;
         col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f;
         col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f;
         col[(i << 2) + 3] = 1.0f;
      }
     
      if (sprite.w > 0 && sprite.h > 1)
      {
         if (1 == YglIsCached(tmp,&cash) )
         {
            YglCacheQuadGrowShading(&sprite, col,&cash);
            return;
         }

         YglQuadGrowShading(&sprite, &texture,col,&cash);
         //YglQuad(&sprite, &texture,&c);
         YglCacheAdd(tmp,&cash);
         Vdp1ReadTexture(&cmd, &sprite, &texture);
         return;
      }
   
   }
   else // No Gouraud shading, use same color for all 4 vertices
   {
      if (sprite.w > 0 && sprite.h > 1)
      {
         if (1 == YglIsCached(tmp,&cash) )
         {
            YglCachedQuad(&sprite, &cash);
            return;
         }

         YglQuad(&sprite, &texture,&cash);
         YglCacheAdd(tmp,&cash);

         Vdp1ReadTexture(&cmd, &sprite, &texture);
      }
   }
   
   return ;
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1PolygonDraw(void)
{
   s16 X[4];
   s16 Y[4];
   u16 color;
   u16 CMDPMOD;
   u8 alpha;
   YglSprite polygon;
   YglTexture texture;
   u16 color2;
   int i;
   float col[4*4];
   int gouraud=0;
   int priority;
   

   polygon.blendmode=0;
   polygon.dst = 0;
   X[0] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC);
   Y[0] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE);
   X[1] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10);
   Y[1] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12);
   X[2] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14);
   Y[2] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16);
   X[3] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x18);
   Y[3] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1A);

   color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x6);
   CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4);
   polygon.uclipmode=(CMDPMOD>>9)&0x03;
   
  
   // Half trans parent to VDP1 Framebuffer
   if( (CMDPMOD & 0x7)==0x03 || (CMDPMOD & 0x100) )
   {
      polygon.blendmode = 0x80;
   }   


   // Check if the Gouraud shading bit is set and the color mode is RGB
   if( (CMDPMOD & 4) )
   {
      for (i=0; i<4; i++)
      {
         color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1));
         col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f;
         col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f;
         col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f;
         col[(i << 2) + 3] = 1.0f;
      }
      gouraud = 1;
   }

   if (color & 0x8000)
      priority = Vdp2Regs->PRISA & 0x7;
   else
   {
      int shadow, colorcalc;
      priority = 0;  // Avoid compiler warning
      Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc);
#ifdef WORDS_BIGENDIAN
      priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1] & 0x7;
#else
      priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7;
#endif
   }

  
   polygon.priority = 8;
     
   polygon.vertices[0] = (int)((float)X[0] * vdp1wratio);
   polygon.vertices[1] = (int)((float)Y[0] * vdp1hratio);
   polygon.vertices[2] = (int)((float)X[1] * vdp1wratio);
   polygon.vertices[3] = (int)((float)Y[1] * vdp1hratio);
   polygon.vertices[4] = (int)((float)X[2] * vdp1wratio);
   polygon.vertices[5] = (int)((float)Y[2] * vdp1hratio);
   polygon.vertices[6] = (int)((float)X[3] * vdp1wratio);
   polygon.vertices[7] = (int)((float)Y[3] * vdp1hratio);

   polygon.w = 1;
   polygon.h = 1;
   polygon.flip = 0;

   if( gouraud == 1 )
   {
       YglQuadGrowShading(&polygon, &texture,col,NULL);
   }else{
      YglQuad(&polygon, &texture,NULL);
   }
   
   if (color == 0)
   {
      alpha = 0;   
      priority = 0;
   }else{
      alpha = 0xF8;
   }
   
   if( (CMDPMOD & 0x100) || (CMDPMOD & 0x7) == 0x3)
   {
      alpha = 0x80;
   }

        
   alpha |= priority;
   
   if (color & 0x8000)
      *texture.textdata = SAT2YAB1(alpha,color);
   else
      *texture.textdata = Vdp2ColorRamGetColor(color, alpha);
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1PolylineDraw(void)
{
   s16 X[4];
   s16 Y[4];
   u16 color;
   u16 CMDPMOD;
   u8 alpha;
   YglSprite polygon;
   YglTexture texture;
   YglCache c;
   int priority;

   polygon.blendmode=0;   
   polygon.dst = 0;
   X[0] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C) );
   Y[0] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E) );
   X[1] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10) );
   Y[1] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12) );
   X[2] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14) );
   Y[2] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16) );
   X[3] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x18) );
   Y[3] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1A) );

   color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x6);
   CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4);
   polygon.uclipmode=(CMDPMOD>>9)&0x03;
   

   // Half trans parent to VDP1 Framebuffer
   if( (CMDPMOD & 0x7)==0x03 || (CMDPMOD & 0x100) )
   {
      polygon.blendmode = 0x80;
   }     
      
   if (color & 0x8000)
      priority = Vdp2Regs->PRISA & 0x7;
   else
   {
      int shadow, colorcalc;

      priority = 0;  // Avoid compiler warning
      Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc);
#ifdef WORDS_BIGENDIAN
      priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1] & 0x7;
#else
      priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7;
#endif
   }
   
   polygon.priority = 8;

   // A bit of kludge, but eventually we'll have to redo the YGL anyways.
   polygon.vertices[0] = (int)((float)X[0] * vdp1wratio);
   polygon.vertices[1] = (int)((float)Y[0] * vdp1hratio);
   polygon.vertices[2] = (int)((float)X[0] * vdp1wratio)+1;
   polygon.vertices[3] = (int)((float)Y[0] * vdp1hratio)+1;
   polygon.vertices[4] = (int)((float)X[1] * vdp1wratio);
   polygon.vertices[5] = (int)((float)Y[1] * vdp1hratio);
   polygon.vertices[6] = (int)((float)X[1] * vdp1wratio)+1;
   polygon.vertices[7] = (int)((float)Y[1] * vdp1hratio)+1;

   polygon.w = 1;
   polygon.h = 1;
   polygon.flip = 0;

   YglQuad(&polygon, &texture,&c);

   polygon.vertices[0] = polygon.vertices[4];
   polygon.vertices[1] = polygon.vertices[5];
   polygon.vertices[2] = polygon.vertices[6];
   polygon.vertices[3] = polygon.vertices[7];
   polygon.vertices[4] = (int)((float)X[2] * vdp1wratio);
   polygon.vertices[5] = (int)((float)Y[2] * vdp1hratio);
   polygon.vertices[6] = (int)((float)X[2] * vdp1wratio)+1;
   polygon.vertices[7] = (int)((float)Y[2] * vdp1hratio)+1;
   YglCachedQuad(&polygon, &c);

   polygon.vertices[0] = polygon.vertices[4];
   polygon.vertices[1] = polygon.vertices[5];
   polygon.vertices[2] = polygon.vertices[6];
   polygon.vertices[3] = polygon.vertices[7];
   polygon.vertices[4] = (int)((float)X[3] * vdp1wratio);
   polygon.vertices[5] = (int)((float)Y[3] * vdp1hratio);
   polygon.vertices[6] = (int)((float)X[3] * vdp1wratio)+1;
   polygon.vertices[7] = (int)((float)Y[3] * vdp1hratio)+1;
   YglCachedQuad(&polygon, &c);

   polygon.vertices[0] = (int)((float)X[0] * vdp1wratio);
   polygon.vertices[1] = (int)((float)Y[0] * vdp1hratio);
   polygon.vertices[2] = (int)((float)X[0] * vdp1wratio)+1;
   polygon.vertices[3] = (int)((float)Y[0] * vdp1hratio)+1;
   YglCachedQuad(&polygon, &c);

   if (color == 0)
   {
      alpha = 0;   
      priority = 0;
   }else{
      alpha = 0xF8;
      if (CMDPMOD & 0x100)
      {
         alpha = 0x80;
      }
   }

   alpha |= priority;
   
   if (color & 0x8000)
      *texture.textdata = SAT2YAB1(alpha,color);
   else
      *texture.textdata = Vdp2ColorRamGetColor(color, alpha);
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1LineDraw(void)
{
   s16 X[2];
   s16 Y[2];
   u16 color;
   u16 CMDPMOD;
   u8 alpha;
   YglSprite polygon;
   YglTexture texture;
   int priority;
   
   polygon.blendmode=0;
   polygon.dst = 0;
   X[0] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C));
   Y[0] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E));
   X[1] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10));
   Y[1] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12));

   color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x6);
   CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4);
   polygon.uclipmode=(CMDPMOD>>9)&0x03;

   // Half trans parent to VDP1 Framebuffer
   if( (CMDPMOD & 0x7)==0x03 || (CMDPMOD & 0x100) )
   {
      polygon.blendmode = 0x80;
   }  

   if (color & 0x8000)
      priority = Vdp2Regs->PRISA & 0x7;
   else
   {
      int shadow, colorcalc;

      priority = 0;  // Avoid compiler warning
      Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc);
#ifdef WORDS_BIGENDIAN
      priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1] & 0x7;
#else
      priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7;
#endif
   }
   
   polygon.priority = 8;

   polygon.vertices[0] = (int)((float)X[0] * vdp1wratio);
   polygon.vertices[1] = (int)((float)Y[0] * vdp1hratio);
   polygon.vertices[2] = (int)((float)X[0] * vdp1wratio)+1;
   polygon.vertices[3] = (int)((float)Y[0] * vdp1hratio)+1;
   polygon.vertices[4] = (int)((float)X[1] * vdp1wratio);
   polygon.vertices[5] = (int)((float)Y[1] * vdp1hratio);
   polygon.vertices[6] = (int)((float)X[1] * vdp1wratio)+1;
   polygon.vertices[7] = (int)((float)Y[1] * vdp1hratio)+1;

   polygon.w = 1;
   polygon.h = 1;
   polygon.flip = 0;

   YglQuad(&polygon, &texture,NULL);
   
   if (color == 0)
   {
      alpha = 0;  
      priority = 0;
   }else{
      alpha = 0xF8;
      if (CMDPMOD & 0x100)
      {
         alpha = 0x80;
      }
   }
   alpha |= priority;
   
   if (color & 0x8000)
      *texture.textdata = SAT2YAB1(alpha,color);
   else
      *texture.textdata = Vdp2ColorRamGetColor(color, alpha);
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1UserClipping(void)
{
   Vdp1Regs->userclipX1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC);
   Vdp1Regs->userclipY1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE);
   Vdp1Regs->userclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14);
   Vdp1Regs->userclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16);
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1SystemClipping(void)
{
   Vdp1Regs->systemclipX1 = 0;
   Vdp1Regs->systemclipY1 = 0;
   Vdp1Regs->systemclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14);
   Vdp1Regs->systemclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16);
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp1LocalCoordinate(void)
{
   Vdp1Regs->localX = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC);
   Vdp1Regs->localY = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE);
}

//////////////////////////////////////////////////////////////////////////////

int VIDOGLVdp2Reset(void)
{
   return 0;
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp2DrawStart(void)
{
   YglReset();
   YglCacheReset();
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp2DrawEnd(void)
{
   YglRender();
}

//////////////////////////////////////////////////////////////////////////////


   
static void Vdp2DrawBackScreen(void)
{
   u32 scrAddr;
   int dot, y;
  
   static unsigned char lineColors[512 * 3];
   static int line[512*4];


   if (Vdp2Regs->VRSIZE & 0x8000)
      scrAddr = (((Vdp2Regs->BKTAU & 0x7) << 16) | Vdp2Regs->BKTAL) * 2;
   else
      scrAddr = (((Vdp2Regs->BKTAU & 0x3) << 16) | Vdp2Regs->BKTAL) * 2;

   if (Vdp2Regs->BKTAU & 0x8000)
   {
      for(y = 0; y < vdp2height_gl; y++)
      {
         dot = T1ReadWord(Vdp2Ram, scrAddr);
         scrAddr += 2;
         
         lineColors[3*y+0] = (dot & 0x1F) << 3;
         lineColors[3*y+1] = (dot & 0x3E0) >> 2;
         lineColors[3*y+2] = (dot & 0x7C00) >> 7;
         line[4*y+0] = 0;
         line[4*y+1] = y;
         line[4*y+2] = vdp2width_gl;
         line[4*y+3] = y;         
      }
      
      glColorPointer(3, GL_UNSIGNED_BYTE, 0, lineColors);
      glEnableClientState(GL_COLOR_ARRAY);
      glVertexPointer(2, GL_INT, 0, line);
      glEnableClientState(GL_VERTEX_ARRAY);
      glDrawArrays(GL_LINES,0,vdp2height_gl*2);
      glDisableClientState(GL_COLOR_ARRAY);      
      glColor3ub(0xFF, 0xFF, 0xFF);
   }
   else
   {
      dot = T1ReadWord(Vdp2Ram, scrAddr);

      glColor3ub((dot & 0x1F) << 3, (dot & 0x3E0) >> 2, (dot & 0x7C00) >> 7);

      line[0] = 0;
      line[1] = 0;
      line[2] = vdp2width_gl;
      line[3] = 0;    
      line[4] = vdp2width_gl;
      line[5] = vdp2height_gl;
      line[6] = 0;
      line[7] = vdp2height_gl;    

      glDisable(GL_TEXTURE_2D);
      glVertexPointer(2, GL_INT, 0, line);
      glEnableClientState(GL_VERTEX_ARRAY);
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      glDrawArrays(GL_TRIANGLE_FAN,0,8);
      glColor3ub(0xFF, 0xFF, 0xFF);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   }
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawLineColorScreen(void)
{
}

 
//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawNBG0(void)
{
   vdp2draw_struct info;
   YglTexture texture;
   YglCache tmpc;
   vdp2rotationparameter_struct parameter;
   info.dst=0;
   info.uclipmode=0;
   
   info.coordincx = 1.0f;
   info.coordincy = 1.0f;

   if (Vdp2Regs->BGON & 0x20)
   {
      // RBG1 mode
      info.enable = Vdp2Regs->BGON & 0x20;

      // Read in Parameter B
      Vdp2ReadRotationTable(1, &parameter);

      if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0)
      {
         // Bitmap Mode

         ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 2, 0x3);

         info.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000;
         info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 4;
         info.flipfunction = 0;
         info.specialfunction = 0;
      }
      else
      {
         // Tile Mode
         info.mapwh = 4;
         ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 12);
         ReadPatternData(&info, Vdp2Regs->PNCN0, Vdp2Regs->CHCTLA & 0x1);
      }

      info.rotatenum = 1;
      info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2ParameterBPlaneAddr;
      parameter.coefenab = Vdp2Regs->KTCTL & 0x100;

      info.LineColorBase = 0x00;
      if (paraB.coefenab)
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01WithK;
      else
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01NoK;
   }
   else if (Vdp2Regs->BGON & 0x1)
   {
      // NBG0 mode
      info.enable = Vdp2Regs->BGON & 0x1;

      if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0)
      {
         // Bitmap Mode

         ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 2, 0x3);

         info.x = - ((Vdp2Regs->SCXIN0 & 0x7FF) % info.cellw);
         info.y = - ((Vdp2Regs->SCYIN0 & 0x7FF) % info.cellh);

         info.charaddr = (Vdp2Regs->MPOFN & 0x7) * 0x20000;
         info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 4;
         info.flipfunction = 0;
         info.specialfunction = 0;
      }
      else
      {
         // Tile Mode
         info.mapwh = 2;

         ReadPlaneSize(&info, Vdp2Regs->PLSZ);

         info.x = - ((Vdp2Regs->SCXIN0 & 0x7FF) % (512 * info.planew));
         info.y = - ((Vdp2Regs->SCYIN0 & 0x7FF) % (512 * info.planeh));
         ReadPatternData(&info, Vdp2Regs->PNCN0, Vdp2Regs->CHCTLA & 0x1);
      }

      if( (Vdp2Regs->ZMXN0.all & 0x7FF00) == 0 )
         info.coordincx = 1.0f; 
      else
         info.coordincx = (float) 65536 / (Vdp2Regs->ZMXN0.all & 0x7FF00);
      
      switch(Vdp2Regs->ZMCTL&0x03)
      {
      case 0:
         break;
      case 1:
         if( info.coordincx < 0.5f )  info.coordincx = 0.5f;
         break;
      case 2:
      case 3:
         if( info.coordincx < 0.25f )  info.coordincx = 0.25f;
         break;
      }

      if( (Vdp2Regs->ZMYN0.all & 0x7FF00) == 0 )
         info.coordincy = 1.0f; 
      else
         info.coordincy = (float) 65536 / (Vdp2Regs->ZMYN0.all & 0x7FF00);
      
      info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2NBG0PlaneAddr;
      

      
   }
   else
      // Not enabled
      return;
   
   info.transparencyenable = !(Vdp2Regs->BGON & 0x100);
   info.specialprimode   = Vdp2Regs->SFPRMD & 0x3;
   info.specialcolormode = Vdp2Regs->SFCCMD & 0x3;

   info.colornumber = (Vdp2Regs->CHCTLA & 0x70) >> 4;

   
   if(Vdp2Regs->CCCTL & 0x1)
   {
      info.alpha = ((~Vdp2Regs->CCRNA & 0x1F) << 3) + 0x7;
      if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0)
         info.blendmode=2;
      else
         info.blendmode=1;
   }else{
      info.alpha = 0xFF;
      info.blendmode=0;
   }

   info.coloroffset = (Vdp2Regs->CRAOFA & 0x7) << 8;
   ReadVdp2ColorOffset(&info, 0x1);
   info.priority = nbg0priority;

   if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0))
      return;
   
   // Window Mode
   info.bEnWin0 = (Vdp2Regs->WCTLA >> 1) &0x01;
   info.WindowArea0 = (Vdp2Regs->WCTLA >> 0) & 0x01;  
   info.bEnWin1 = (Vdp2Regs->WCTLA >> 3) &0x01;
   info.WindowArea1 = (Vdp2Regs->WCTLA >> 2) & 0x01; 
   info.LogicWin    = (Vdp2Regs->WCTLA >> 7 ) & 0x01;
   
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin);
   
   ReadLineScrollData(&info, Vdp2Regs->SCRCTL & 0xFF, Vdp2Regs->LSTA0.all);
   info.lineinfo = lineNBG0;
   Vdp2GenLineinfo( &info );
   Vdp2SetGetColor( &info );

   if (info.enable == 1)
   {
      // NBG0 draw
      if (info.isbitmap)
      {
         int xx,yy;
         int isCached = 0;
      
         if(info.islinescroll) // Nights Movie
         {
            info.sh = (Vdp2Regs->SCXIN0 & 0x7FF);
            info.sv = (Vdp2Regs->SCYIN0 & 0x7FF);
            info.x = 0;
            info.y = 0;
         }

         yy = info.y;
         while( yy < vdp2height_gl )
         {
            xx = info.x;
            while( xx < vdp2width_gl )
            {
               info.vertices[0] = xx * info.coordincx;
               info.vertices[1] = yy * info.coordincy;
               info.vertices[2] = (xx + info.cellw) * info.coordincx;
               info.vertices[3] = yy * info.coordincy;
               info.vertices[4] = (xx + info.cellw) * info.coordincx;
               info.vertices[5] = (yy + info.cellh) * info.coordincy;
               info.vertices[6] = xx * info.coordincx;
               info.vertices[7] = (yy + info.cellh) * info.coordincy;            

               if( isCached == 0 )
               {
                  YglQuad((YglSprite *)&info, &texture,&tmpc);
                  Vdp2DrawCell(&info, &texture);               
                  isCached = 1;
               }else{
                  YglCachedQuad((YglSprite *)&info, &tmpc);
               }
               xx += info.cellw* info.coordincx;
            }
            yy += info.cellh* info.coordincy;
         }
      
      }
      else
      {
         Vdp2DrawMap(&info, &texture);
      }
   }
   else
   {
      // RBG1 draw
      Vdp2DrawRotation(&info, &parameter, &texture);
   }
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglEndWindow(&info);
   
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawNBG1(void)
{
   vdp2draw_struct info;
   YglTexture texture;
   YglCache tmpc;
   info.dst=0;
   info.uclipmode=0;
   
   info.enable = Vdp2Regs->BGON & 0x2;
   info.transparencyenable = !(Vdp2Regs->BGON & 0x200);
   info.specialprimode = (Vdp2Regs->SFPRMD >> 2) & 0x3;

   info.colornumber = (Vdp2Regs->CHCTLA & 0x3000) >> 12;

   if((info.isbitmap = Vdp2Regs->CHCTLA & 0x200) != 0)
   {
      ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 10, 0x3);

      info.x = -((Vdp2Regs->SCXIN1 & 0x7FF) % info.cellw);
      info.y = -((Vdp2Regs->SCYIN1 & 0x7FF) % info.cellh);
      info.charaddr = ((Vdp2Regs->MPOFN & 0x70) >> 4) * 0x20000;
      info.paladdr = (Vdp2Regs->BMPNA & 0x700) >> 4;
      info.flipfunction = 0;
      info.specialfunction = 0;
   }
   else
   {
      info.mapwh = 2;

      ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 2);

      info.x = - ((Vdp2Regs->SCXIN1 & 0x7FF) % (512 * info.planew));
      info.y = - ((Vdp2Regs->SCYIN1 & 0x7FF) % (512 * info.planeh));

      ReadPatternData(&info, Vdp2Regs->PNCN1, Vdp2Regs->CHCTLA & 0x100);
   }

   info.specialcolormode = (Vdp2Regs->SFCCMD>>2) & 0x3;

   if (Vdp2Regs->CCCTL & 0x2)
   {
      info.alpha = ((~Vdp2Regs->CCRNA & 0x1F00) >> 5) + 0x7;
      if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 )
      {
         info.blendmode=2;
      }else{
         info.blendmode=1;
      }
   }else{
      info.alpha = 0xFF;
      info.blendmode=0;
   }

   info.coloroffset = (Vdp2Regs->CRAOFA & 0x70) << 4;
   ReadVdp2ColorOffset(&info, 0x2);

   if( (Vdp2Regs->ZMXN1.all & 0x7FF00) == 0 )
      info.coordincx = 1.0f; 
   else
      info.coordincx = (float) 65536 / (Vdp2Regs->ZMXN1.all & 0x7FF00);
      
   switch((Vdp2Regs->ZMCTL>>8)&0x03)
   {
   case 0:
      break;
   case 1:
      if( info.coordincx < 0.5f )  info.coordincx = 0.5f;
      break;
   case 2:
   case 3:
      if( info.coordincx < 0.25f )  info.coordincx = 0.25f;
      break;
   }

      if( (Vdp2Regs->ZMYN1.all & 0x7FF00) == 0 )
         info.coordincy = 1.0f; 
      else
         info.coordincy = (float) 65536 / (Vdp2Regs->ZMYN1.all & 0x7FF00);
      
      
   info.priority = nbg1priority;
   info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2NBG1PlaneAddr;

   if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0))
      return;
   
   // Window Mode
   info.bEnWin0 = (Vdp2Regs->WCTLA >> 9) &0x01;
   info.WindowArea0 = (Vdp2Regs->WCTLA >> 8) & 0x01;  
   info.bEnWin1 = (Vdp2Regs->WCTLA >> 11) &0x01;
   info.WindowArea1 = (Vdp2Regs->WCTLA >> 10) & 0x01; 
   info.LogicWin    = (Vdp2Regs->WCTLA >> 15 ) & 0x01;
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin);
   
   ReadLineScrollData(&info, Vdp2Regs->SCRCTL >> 8, Vdp2Regs->LSTA1.all);
   info.lineinfo = lineNBG1;
   Vdp2GenLineinfo( &info );
   Vdp2SetGetColor( &info );
#if 0   
   if(info->islinescroll)
   {
      int y = info->y;
      if( VDPLINE_SX(info->islinescroll) ) info->x += info->lineinfo[y].LineScrollValH;
      if( VDPLINE_SY(info->islinescroll) )info->y += info->lineinfo[y].LineScrollValH;
   }  
#endif   
   
   if (info.isbitmap)
   {
      int xx,yy;
      int isCached = 0;
      if(info.islinescroll)
      {
          info.sh = (Vdp2Regs->SCXIN1 & 0x7FF);
          info.sv = (Vdp2Regs->SCYIN1 & 0x7FF);
          info.x = 0;
          info.y = 0;
      }
      
      yy = info.y;
      while( yy < vdp2height_gl )
      {
         xx = info.x;
         while( xx < vdp2width_gl )
         {
            info.vertices[0] = xx * info.coordincx;
            info.vertices[1] = yy * info.coordincy;
            info.vertices[2] = (xx + info.cellw) * info.coordincx;
            info.vertices[3] = yy * info.coordincy;
            info.vertices[4] = (xx + info.cellw) * info.coordincx;
            info.vertices[5] = (yy + info.cellh) * info.coordincy;
            info.vertices[6] = xx * info.coordincx;
            info.vertices[7] = (yy + info.cellh) * info.coordincy;            

            if( isCached == 0 )
            {
               YglQuad((YglSprite *)&info, &texture,&tmpc);
               Vdp2DrawCell(&info, &texture);               
               isCached = 1;
            }else{
               YglCachedQuad((YglSprite *)&info, &tmpc);
            }
            xx += info.cellw* info.coordincx;
         }
         yy += info.cellh* info.coordincy;
      }
      
   }
   else
      Vdp2DrawMap(&info, &texture);
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglEndWindow(&info);   
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawNBG2(void)
{
   vdp2draw_struct info;
   YglTexture texture;
   info.dst=0;
   info.uclipmode=0;
   
   info.enable = Vdp2Regs->BGON & 0x4;
   info.transparencyenable = !(Vdp2Regs->BGON & 0x400);
   info.specialprimode = (Vdp2Regs->SFPRMD >> 4) & 0x3;

   info.colornumber = (Vdp2Regs->CHCTLB & 0x2) >> 1;
   info.mapwh = 2;

   ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 4);
   info.x = - ((Vdp2Regs->SCXN2 & 0x7FF) % (512 * info.planew));
   info.y = - ((Vdp2Regs->SCYN2 & 0x7FF) % (512 * info.planeh));
   ReadPatternData(&info, Vdp2Regs->PNCN2, Vdp2Regs->CHCTLB & 0x1);

   info.specialcolormode = (Vdp2Regs->SFCCMD>>4) & 0x3;

   if (Vdp2Regs->CCCTL & 0x4)
   {
      info.alpha = ((~Vdp2Regs->CCRNB & 0x1F) << 3) + 0x7;
      if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 )
      {
         info.blendmode=2;
      }else{
         info.blendmode=1;
      }
   }else{
      info.alpha = 0xFF;
      info.blendmode=0;
   }

   info.coloroffset = Vdp2Regs->CRAOFA & 0x700;
   ReadVdp2ColorOffset(&info, 0x4);
   info.coordincx = info.coordincy = 1;

   info.priority = nbg2priority;
   info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2NBG2PlaneAddr;

   if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0))
      return;
   
   // Window Mode
   info.bEnWin0 = (Vdp2Regs->WCTLB >> 1) &0x01;
   info.WindowArea0 = (Vdp2Regs->WCTLB >> 0) & 0x01;  
   info.bEnWin1 = (Vdp2Regs->WCTLB >> 3) &0x01;
   info.WindowArea1 = (Vdp2Regs->WCTLB >> 2) & 0x01;    
   info.LogicWin    = (Vdp2Regs->WCTLB >> 7 ) & 0x01;

   Vdp2SetGetColor( &info );   
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin);
   
   info.islinescroll = 0;
   info.linescrolltbl = 0;
   info.lineinc = 0;   

   Vdp2DrawMap(&info, &texture);
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglEndWindow(&info);   
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawNBG3(void)
{
   vdp2draw_struct info;
   YglTexture texture;
   info.dst=0;
   info.uclipmode=0;
   
   info.enable = Vdp2Regs->BGON & 0x8;
   info.transparencyenable = !(Vdp2Regs->BGON & 0x800);
   info.specialprimode = (Vdp2Regs->SFPRMD >> 6) & 0x3;

   info.colornumber = (Vdp2Regs->CHCTLB & 0x20) >> 5;

   info.mapwh = 2;

   ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 6);
   info.x = - ((Vdp2Regs->SCXN3 & 0x7FF) % (512 * info.planew));
   info.y = - ((Vdp2Regs->SCYN3 & 0x7FF) % (512 * info.planeh));
   ReadPatternData(&info, Vdp2Regs->PNCN3, Vdp2Regs->CHCTLB & 0x10);

   info.specialcolormode = (Vdp2Regs->SFCCMD>>6) & 0x03;
   
   if (Vdp2Regs->CCCTL & 0x8)
   {
      info.alpha = ((~Vdp2Regs->CCRNB & 0x1F00) >> 5) + 0x7;
      if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 )
      {
         info.blendmode=2;
      }else{
         info.blendmode=1;
      }
   }else{
      info.alpha = 0xFF;
      info.blendmode=0;
   }
   
   info.coloroffset = (Vdp2Regs->CRAOFA & 0x7000) >> 4;
   ReadVdp2ColorOffset(&info, 0x8);
   info.coordincx = info.coordincy = 1;

   info.priority = nbg3priority;
   info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2NBG3PlaneAddr;

   if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0))
      return;
 
   // Window Mode
   info.bEnWin0 = (Vdp2Regs->WCTLB >> 9) &0x01;
   info.WindowArea0 = (Vdp2Regs->WCTLB >> 8) & 0x01;
   info.bEnWin1 = (Vdp2Regs->WCTLB >> 11) &0x01;
   info.WindowArea1 = (Vdp2Regs->WCTLB >> 10) & 0x01;
   info.LogicWin    = (Vdp2Regs->WCTLB >> 15 ) & 0x01;
   
   Vdp2SetGetColor( &info );   

   if( info.bEnWin0 || info.bEnWin1 )
      YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin);
   
   info.islinescroll = 0;
   info.linescrolltbl = 0;
   info.lineinc = 0;   
   
   Vdp2DrawMap(&info, &texture);
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglEndWindow(&info);   
}

//////////////////////////////////////////////////////////////////////////////

static void Vdp2DrawRBG0(void)
{
   vdp2draw_struct info;
   YglTexture texture;
   vdp2rotationparameter_struct parameter;
   info.dst=0;
   info.uclipmode=0;
   
   info.enable = Vdp2Regs->BGON & 0x10;
   info.priority = rbg0priority;
   if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0))
      return;
   info.transparencyenable = !(Vdp2Regs->BGON & 0x1000);
   info.specialprimode = (Vdp2Regs->SFPRMD >> 8) & 0x3;

   info.colornumber = (Vdp2Regs->CHCTLB & 0x7000) >> 12;

   info.bEnWin0     = (Vdp2Regs->WCTLC >> 1) & 0x01;
   info.WindowArea0 = (Vdp2Regs->WCTLC >> 0) & 0x01;

   info.bEnWin1     = (Vdp2Regs->WCTLC >> 3) & 0x01;
   info.WindowArea1 = (Vdp2Regs->WCTLC >> 2) & 0x01;

   info.LogicWin    = (Vdp2Regs->WCTLC >> 7 ) & 0x01;

   info.islinescroll = 0;
   info.linescrolltbl = 0;
   info.lineinc = 0;   
   
   Vdp2ReadRotationTable(0, &paraA);
   Vdp2ReadRotationTable(1, &paraB);
   paraA.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2ParameterAPlaneAddr;
   paraB.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2ParameterBPlaneAddr;
   paraA.charaddr = (Vdp2Regs->MPOFR & 0x7) * 0x20000;
   paraB.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000;
   ReadPlaneSizeR(&paraA,Vdp2Regs->PLSZ >> 8);
   ReadPlaneSizeR(&paraB,Vdp2Regs->PLSZ >> 12);
   
    
    
    if( paraA.coefdatasize == 2)
    {
        if(paraA.coefmode < 3 )
        {
            info.GetKValueA = vdp2rGetKValue1W;
        }else{
            info.GetKValueA = vdp2rGetKValue1Wm3;
        }

    }else{
        if(paraA.coefmode < 3 )
        {
            info.GetKValueA = vdp2rGetKValue2W;
        }else{
            info.GetKValueA = vdp2rGetKValue2Wm3;
        }
    }

    if( paraB.coefdatasize == 2)
    {
        if(paraB.coefmode < 3 )
        {
            info.GetKValueB = vdp2rGetKValue1W;
        }else{
            info.GetKValueB = vdp2rGetKValue1Wm3;
        }

    }else{
        if(paraB.coefmode < 3 )
        {
            info.GetKValueB = vdp2rGetKValue2W;
        }else{
            info.GetKValueB = vdp2rGetKValue2Wm3;
        }
    }

   if( Vdp2Regs->RPMD == 0x00 )
   {
      if(!(paraA.coefenab))
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode00NoK;
      }else{
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode00WithK;
      }

   }else if( Vdp2Regs->RPMD == 0x01 )
   {
      if(!(paraB.coefenab))
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01NoK;
      }else{
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01WithK;
      }

   }else if( Vdp2Regs->RPMD == 0x02 )
   {
      if(!(paraA.coefenab))
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode02NoK;
      }else{
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode02WithKA;
      }

   }else if( Vdp2Regs->RPMD == 0x03 )
   {
      // Window0
      if( ((Vdp2Regs->WCTLD >> 1) & 0x01) == 0x01 )
      {
         info.pWinInfo = m_vWindinfo0;
         info.WindwAreaMode = (Vdp2Regs->WCTLD & 0x01) ;
      }else if(  ((Vdp2Regs->WCTLD >> 3) & 0x01) == 0x01 )
      {
         info.pWinInfo = m_vWindinfo1;
         info.WindwAreaMode = ((Vdp2Regs->WCTLD >>2)& 0x01) ;
      }else{
         info.pWinInfo = m_vWindinfo0;
         info.WindwAreaMode = (Vdp2Regs->WCTLD & 0x01) ;
      }

      if( paraA.coefenab == 0 && paraB.coefenab == 0 )
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03NoK;
      }else if( paraA.coefenab && paraB.coefenab == 0 )
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03WithKA;
      }else if( paraA.coefenab == 0 && paraB.coefenab )
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03WithKB;
      }else if( paraA.coefenab && paraB.coefenab )
      {
         info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03WithK;
      }
   }
   
   
   paraA.screenover = (Vdp2Regs->PLSZ >> 10)  & 0x03;
   paraB.screenover = (Vdp2Regs->PLSZ >> 14)  & 0x03;

   
   
   // Figure out which Rotation Parameter we're using
   switch (Vdp2Regs->RPMD & 0x3)
   {
      case 0:
         // Parameter A
         info.rotatenum = 0;
         info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2ParameterAPlaneAddr;
         break;
      case 1:
         // Parameter B
         info.rotatenum = 1;
         info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2ParameterBPlaneAddr;
         break;
      case 2:
         // Parameter A+B switched via coefficients
         // FIX ME(need to figure out which Parameter is being used)
      case 3:
      default:
         // Parameter A+B switched via rotation parameter window
         // FIX ME(need to figure out which Parameter is being used)
         VDP2LOG("Rotation Parameter Mode %d not supported!\n", Vdp2Regs->RPMD & 0x3);
         info.rotatenum = 0;
         info.PlaneAddr = (void FASTCALL (*)(void *, int))&Vdp2ParameterAPlaneAddr;
         break;
   }

   

   if((info.isbitmap = Vdp2Regs->CHCTLB & 0x200) != 0)
   {
      // Bitmap Mode
      ReadBitmapSize(&info, Vdp2Regs->CHCTLB >> 10, 0x1);

      if (info.rotatenum == 0)
         // Parameter A
         info.charaddr = (Vdp2Regs->MPOFR & 0x7) * 0x20000;
      else
         // Parameter B
         info.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000;

      info.paladdr = (Vdp2Regs->BMPNB & 0x7) << 4;
      info.flipfunction = 0;
      info.specialfunction = 0;
   }
   else
   {
      int i;
      // Tile Mode
      info.mapwh = 4;

      if (info.rotatenum == 0)
         // Parameter A
         ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 8);
      else
         // Parameter B
         ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 12);

      ReadPatternData(&info, Vdp2Regs->PNCR, Vdp2Regs->CHCTLB & 0x100);
  
      paraA.ShiftPaneX = 8 + paraA.planew;
      paraA.ShiftPaneY = 8 + paraA.planeh;
      paraB.ShiftPaneX = 8 + paraB.planew;
      paraB.ShiftPaneY = 8 + paraB.planeh;      

      paraA.MskH = (8 * 64 * paraA.planew)-1;
      paraA.MskV = (8 * 64 * paraA.planeh)-1;
      paraB.MskH = (8 * 64 * paraB.planew)-1;
      paraB.MskV = (8 * 64 * paraB.planeh)-1;
    
	   paraA.MaxH = 8 * 64 * paraA.planew * 4;
	   paraA.MaxV = 8 * 64 * paraA.planeh * 4;
	   paraB.MaxH = 8 * 64 * paraB.planew * 4;
	   paraB.MaxV = 8 * 64 * paraB.planeh * 4;

	   if( paraA.screenover == OVERMODE_512 )
	   {
		   paraA.MaxH = 512;
		   paraA.MaxV = 512;
	   }

	   if( paraB.screenover == OVERMODE_512 )
	   {
		   paraB.MaxH = 512;
		   paraB.MaxV = 512;
	   }
	   
	   for( i=0; i<16; i++ )
       {
         paraA.PlaneAddr(&info,i);
         paraA.PlaneAddrv[i] = info.addr;
         paraB.PlaneAddr(&info,i);
         paraB.PlaneAddrv[i] = info.addr;
       }
   }

   info.specialcolormode = (Vdp2Regs->SFCCMD>>8) & 0x03;
   
   info.blendmode=0;         
   if( (Vdp2Regs->LNCLEN & 0x10) == 0x00 )
   {
      if (Vdp2Regs->CCCTL & 0x10)
      {
         info.alpha = ((~Vdp2Regs->CCRR & 0x1F) << 3) + 0x7;
         if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 )
         {
            info.blendmode=2;
         }else{
            info.blendmode=1;         
         }
      }else{
         info.alpha = 0xFF;
      }
      info.LineColorBase = 0x00;
      paraA.lineaddr = 0xFFFFFFFF;
      paraB.lineaddr = 0xFFFFFFFF;
   }else{
      info.alpha = 0xFF;
      info.LineColorBase = (Vdp2Regs->LCTA.all) << 1;
      if( info.LineColorBase >= 0x80000 ) info.LineColorBase = 0x00;
      paraA.lineaddr = 0xFFFFFFFF;
      paraB.lineaddr = 0xFFFFFFFF;
   }



   info.coloroffset = (Vdp2Regs->CRAOFB & 0x7) << 8;

   ReadVdp2ColorOffset(&info, 0x10);
   info.coordincx = info.coordincy = 1;
   
   // Window Mode
   info.bEnWin0 = (Vdp2Regs->WCTLC >> 1) &0x01;
   info.WindowArea0 = (Vdp2Regs->WCTLC >> 0) & 0x01;  
   info.bEnWin1 = (Vdp2Regs->WCTLC >> 3) &0x01;
   info.WindowArea1 = (Vdp2Regs->WCTLC >> 2) & 0x01;    
   info.LogicWin    = (Vdp2Regs->WCTLC >> 7 ) & 0x01;
   
   Vdp2SetGetColor( &info );   

   if( info.bEnWin0 || info.bEnWin1 )
      YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin);
   
   Vdp2DrawRotation(&info, &parameter, &texture);
   
   if( info.bEnWin0 || info.bEnWin1 )
      YglEndWindow(&info);   
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp2DrawScreens(void)
{
   Vdp2GenerateWindowInfo();
   Vdp2DrawBackScreen();
   Vdp2DrawLineColorScreen();
   Vdp2DrawNBG3();
   Vdp2DrawNBG2();
   Vdp2DrawNBG1();
   Vdp2DrawNBG0();
   Vdp2DrawRBG0();
}

//////////////////////////////////////////////////////////////////////////////

void VIDOGLVdp2SetResolution(u16 TVMD)
{
   int width=0, height=0;
   int wratio=1, hratio=1;

   // Horizontal Resolution
   switch (TVMD & 0x7)
   {
      case 0:
         width = 320;
         wratio = 1;
         break;
      case 1:
         width = 352;
         wratio = 1;
         break;
      case 2:
         width = 640;
         wratio = 2;
         break;
      case 3:
         width = 704;
         wratio = 2;
         break;
      case 4:
         width = 320;
         wratio = 1;
         break;
      case 5:
         width = 352;
         wratio = 1;
         break;
      case 6:
         width = 640;
         wratio = 2;
         break;
      case 7:
         width = 704;
         wratio = 2;
         break;
   }

   // Vertical Resolution
   switch ((TVMD >> 4) & 0x3)
   {
      case 0:
         height = 224;
         break;
      case 1: height = 240;
                 break;
      case 2: height = 256;
                 break;
      default: break;
   }

   hratio = 1;

   // Check for interlace
   switch ((TVMD >> 6) & 0x3)
   {
      case 3: // Double-density Interlace
         height *= 2;
         hratio = 2;
         break;
      case 2: // Single-density Interlace
      case 0: // Non-interlace
      default: break;
   }

   SetSaturnResolution(width, height);
   Vdp1SetTextureRatio(wratio, hratio);
}

//////////////////////////////////////////////////////////////////////////////

void FASTCALL VIDOGLVdp2SetPriorityNBG0(int priority)
{
   nbg0priority = priority;
}

//////////////////////////////////////////////////////////////////////////////

void FASTCALL VIDOGLVdp2SetPriorityNBG1(int priority)
{
   nbg1priority = priority;
}

//////////////////////////////////////////////////////////////////////////////

void FASTCALL VIDOGLVdp2SetPriorityNBG2(int priority)
{
   nbg2priority = priority;
}

//////////////////////////////////////////////////////////////////////////////

void FASTCALL VIDOGLVdp2SetPriorityNBG3(int priority)
{
   nbg3priority = priority;
}

//////////////////////////////////////////////////////////////////////////////

void FASTCALL VIDOGLVdp2SetPriorityRBG0(int priority)
{
   rbg0priority = priority;
}

//////////////////////////////////////////////////////////////////////////////

void YglGetGlSize(int *width, int *height)
{
   *width = GlWidth;
   *height = GlHeight;
}

vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2W( vdp2rotationparameter_struct * param, int index )
{
   float kval;
   int   kdata;
      
   kdata = T1ReadLong(Vdp2Ram, (param->coeftbladdr&0x7FFFF) + (index<<2) );
   if( kdata & 0x80000000 ) return NULL;

   kval = (float) (int) ((kdata & 0x00FFFFFF) | (kdata & 0x00800000 ? 0xFF800000 : 0x00000000)) / 65536.0f;
    
   switch( param->coefmode )
   {
   case 0: 
       param->kx = kval;
       param->ky = kval;
       break;
   case 1: 
       param->kx = kval;
       break;
   case 2: 
       param->ky = kval;
       break;
   }

   param->lineaddr = (kdata >> 24)&0x7F;
   return param;
}

vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1W( vdp2rotationparameter_struct * param, int index )
{
   float kval;
   u16   kdata;
  
   kdata = T1ReadWord(Vdp2Ram, param->coeftbladdr + (index<<1) );
   if( kdata & 0x8000 ) return NULL;

   kval = (float) (signed) ((kdata & 0x7FFF) | (kdata & 0x4000 ? 0x8000 : 0x0000)) / 1024.0f;
   
   switch( param->coefmode )
   {
   case 0: 
       param->kx = kval;
       param->ky = kval;
       break;
   case 1: 
       param->kx = kval;
       break;
   case 2: 
       param->ky = kval;
       break;
   }
   return param;
   
}

vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2Wm3( vdp2rotationparameter_struct * param, int index )
{
   return param; // ToDo:
}

vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1Wm3( vdp2rotationparameter_struct * param, int index )
{
   return param; // ToDo:   
}


vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00NoK( vdp2draw_struct * info, int h, int v )
{
   return &paraA;
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00WithK( vdp2draw_struct * info,int h, int v )
{
   h = paraA.KtablV+(paraA.deltaKAx * h);
   return info->GetKValueA( &paraA, h );
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01NoK( vdp2draw_struct * info,int h, int v )
{
    return &paraB;   
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01WithK( vdp2draw_struct * info,int h, int v )
{
   h = (paraB.KtablV+(paraB.deltaKAx * h));
   return info->GetKValueB( &paraB, h );   
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02NoK( vdp2draw_struct * info,int h, int v )
{
   return &paraA;
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKA( vdp2draw_struct * info,int h, int v )
{
    h = (paraA.KtablV+(paraA.deltaKAx * h));
    if( info->GetKValueA( &paraA, h ) == NULL )
    {
        return &paraB;
    }
    return &paraA;
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKB( vdp2draw_struct * info,int h, int v )
{
   return &paraA;   
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03NoK( vdp2draw_struct * info,int h, int v )
{
   if( info->WindwAreaMode == 0 )
   {
      if( info->pWinInfo[v].WinShowLine == 0  )
      {
         return (&paraB);
      }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            return (&paraB);
         }else{
            return (&paraA);
         }
      }
   }
   else
   {
      if( info->pWinInfo[v].WinShowLine == 0 )
      {
         return (&paraB);
      }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            return (&paraA);
         }else{
            return (&paraB);
         }
      }
   }
   return NULL;   
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKA( vdp2draw_struct * info,int h, int v )
{
  
    if( info->WindwAreaMode == 0 )
   {
      if( info->pWinInfo[v].WinShowLine == 0 )
      {
         return (&paraB);
      }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            return (&paraB);
         }else{
            h = (paraA.KtablV+(paraA.deltaKAx * h));
            return info->GetKValueA( &paraA, h );
         }
      }
   }else{
        if( info->pWinInfo[v].WinShowLine == 0 )
        {
            h = (paraA.KtablV+(paraA.deltaKAx * h));
            return info->GetKValueA( &paraA, h );
        }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            h = (paraA.KtablV+(paraA.deltaKAx * h));
            return info->GetKValueA( &paraA, h );
         }else{
            return (&paraB);
         }
      }
   }
   return NULL;

}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKB( vdp2draw_struct * info,int h, int v )
{
   if( info->WindwAreaMode == 0 )
   {
      if( info->pWinInfo[v].WinShowLine == 0 )
      {
         h = (paraB.KtablV+(paraB.deltaKAx * h));
         return info->GetKValueB( &paraB, h );
      }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            h = (paraB.KtablV+(paraB.deltaKAx * h));
            return info->GetKValueB( &paraB, h );
         }else{
            return &paraA;
         }
      }
   }else{
      {
        if( info->pWinInfo[v].WinShowLine == 0 )
        {
            return &paraA;
        }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            h = (paraA.KtablV+(paraA.deltaKAx * h));
            return info->GetKValueA( &paraA, h );
         }else{
            h = (paraB.KtablV+(paraB.deltaKAx * h));
            return info->GetKValueB( &paraB, h );
         }
         }
      }
   }
   return NULL;
}

vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithK( vdp2draw_struct * info,int h, int v )
{

   if( info->WindwAreaMode == 0 )
   {
      if( info->pWinInfo[v].WinShowLine == 0 )
      {
         h = (paraB.KtablV+(paraB.deltaKAx * h));
         return info->GetKValueB( &paraB, h );
      }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            h = (paraB.KtablV+(paraB.deltaKAx * h));
            return info->GetKValueB( &paraB, h );
         }else{
            h = (paraA.KtablV+(paraA.deltaKAx * h));
            return info->GetKValueA( &paraA, h );
         }
      }
   }else{
      if( info->pWinInfo[v].WinShowLine == 0 )
      {
            h = (paraB.KtablV+(paraB.deltaKAx * h));
            return info->GetKValueB( &paraB, h );
      }else{
         if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd )
         {
            h = (paraB.KtablV+(paraB.deltaKAx * h));
            return info->GetKValueB( &paraB, h );
         }else{
            h = (paraA.KtablV+(paraA.deltaKAx * h));
            return info->GetKValueA( &paraA, h );
         }
      }
   }

   return NULL;
}


#endif

