/**************************************************************************************

                                  DRAW.CPP

***************************************************************************************/

#include "tde.h"

/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
      a_lTableMM : Min-max array
      contains :
      | X_l | X_r | X_t_l | Y_t_l | X_t_r | Y_t_r | blank | blank |
      
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/
TDE_tdl1616 a_lTableMM[768][8];

/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
        Semi-transparency masks for 16 bits
        Force to 0 each component's last bit
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/
unsigned short sMask_565 = 0xF7DE;     // 1111 0111 1101 1110
unsigned short sMask_655 = 0xFBDE;     // 1111 1011 1101 1110
unsigned short sMask_556 = 0xF7BE;     // 1111 0111 1011 1110
unsigned short sMask_555 = 0x7BDE;     // 0111 1011 1101 1110

/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vDrawSuperObject16
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Display a super object (for sprites)
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/

void TDE_vDrawSuperObject16(GLD_tdpstViewportAttributes p_stViewAttrib,
                             TDE_tdsSuperObject *p_stSuperObject)
{
    TDE_tdxValue     xScaledSpriteW, xScaledSpriteH, xSpriteCenterX, xSpriteCenterY, 
                     xSpriteCornerX, xSpriteCornerY, xScaledSourceW, xScaledSourceH,
                     xSourceCornerX, xSourceCornerY;                
    long             lPitchDest, lPitchSrc, lViewPortW, lViewPortH;                                        
    short           si;   
    TDE_tdsRect      stSrcRect, stDestRect;
    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;
    
    stSrcRect.lPitch =  lPitchSrc  = ((long)(p_stSprite->stPicture.xSrcPitch))>>C_TDEDEC; 
    stDestRect.lPitch = lPitchDest = (p_stViewAttrib->lPitch)>>C_TDEDEC;
    lViewPortW = p_stViewAttrib->dwWidth;
    lViewPortH = p_stViewAttrib->dwHeight;
        
// xValues
    xScaledSpriteW = TDE_M_Mul(lViewPortW , p_stSprite->stDim.xX);
    xScaledSpriteH = TDE_M_Mul(lViewPortH , p_stSprite->stDim.xY);    
    xSpriteCenterX = TDE_M_Mul(lViewPortW , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xX);
    xSpriteCenterY = TDE_M_Mul(lViewPortH , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xY);
    xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW,2);
    xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH,2);
    xSourceCornerX = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stSourceOrigin.xX);
    xSourceCornerY = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stSourceOrigin.xY);    
    xScaledSourceW = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stDim.xX);
    xScaledSourceH = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stDim.xY);

    // Destination rectangle
    iTDE_vFillsRect(&stDestRect, xSpriteCornerX - xSpriteCenterX, xSpriteCornerY - xSpriteCenterY,
                                 xScaledSpriteW, xScaledSpriteH);

    // Transformation    
    for (si=0; si<4; si++)
    {                
       TDE_vMulMatrixByVertex(&(p_stSuperObject->stModifiedMatrix.a4_xS), &(stDestRect.tdsSommet[si]), &(stDestRect.tdsSommet[si]));
       stDestRect.tdsSommet[si].xX += xSpriteCenterX;
       stDestRect.tdsSommet[si].xY += xSpriteCenterY;       
    }
    
    // Source rectangle
    iTDE_vFillsRect(&stSrcRect, xSourceCornerX, xSourceCornerY, xScaledSourceW, xScaledSourceH);    

    stDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);
    stSrcRect.p_usPointer = (TDE_tdxPixel *)(p_stSprite->stPicture.lp_Data);

    if (!p_stSprite->cSemiTransparent)
         { iTDE_vBlit(&stSrcRect, &stDestRect); }
    else         
         { iTDE_vBlit_Transparency(&stSrcRect, &stDestRect, p_stSprite->alpha); }
}


/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vDrawSuperObjectFast16
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Display a super object (for sprites) without stretch
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/

void TDE_vDrawSuperObjectFast16(GLD_tdpstViewportAttributes p_stViewAttrib,
                                TDE_tdsSuperObject *p_stSuperObject)
{
    TDE_tdxValue     xScaledSpriteW, xScaledSpriteH, xSpriteCenterX, xSpriteCenterY, 
                     xSpriteCornerX, xSpriteCornerY, xScaledSourceW, xScaledSourceH,
                     xSourceCornerX, xSourceCornerY;                
    long            lPitchDest, lPitchSrc, lViewPortW, lViewPortH;                                        
    short           si;   
    TDE_tdsRect      stSrcRect, stDestRect;
    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;
    
    stSrcRect.lPitch =  lPitchSrc  = ((long)(p_stSprite->stPicture.xSrcPitch))>>C_TDEDEC; 
    stDestRect.lPitch = lPitchDest = (p_stViewAttrib->lPitch)>>C_TDEDEC;
    lViewPortW = p_stViewAttrib->dwWidth;
    lViewPortH = p_stViewAttrib->dwHeight;
        
// xValues
    xSourceCornerX = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stSourceOrigin.xX);
    xSourceCornerY = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stSourceOrigin.xY);    
    xScaledSourceW = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stDim.xX);
    xScaledSourceH = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stDim.xY);
    xScaledSpriteW = xScaledSourceW;
    xScaledSpriteH = xScaledSourceH;    
    xSpriteCenterX = TDE_M_Mul(lViewPortW , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xX);
    xSpriteCenterY = TDE_M_Mul(lViewPortH , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xY);
    xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW,2);
    xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH,2);

    // Destination rectangle
    iTDE_vFillsRect(&stDestRect, xSpriteCornerX - xSpriteCenterX, xSpriteCornerY - xSpriteCenterY,
                    xScaledSpriteW, xScaledSpriteH);

    for (si=0; si<4; si++)
    {                
       stDestRect.tdsSommet[si].xX += xSpriteCenterX;
       stDestRect.tdsSommet[si].xY += xSpriteCenterY;       
    }
    
    // Source rectangle
    iTDE_vFillsRect(&stSrcRect, xSourceCornerX, xSourceCornerY, xScaledSourceW, xScaledSourceH);    

    stDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);
    stSrcRect.p_usPointer = (TDE_tdxPixel *)(p_stSprite->stPicture.lp_Data);

    iTDE_vBlitFast(&stSrcRect, &stDestRect);
}


/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vFastDrawMemorySpriteAbsolute
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Display a sprite stored in memory
 ! ATTENTION ! : The sprite has to be defined with absolute coordinates
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/
void TDE_vFastDrawMemorySpriteAbsolute(GLD_tdpstViewportAttributes p_stViewAttrib,
                                       TDE_tdsSuperObject *p_stSuperObject,
                                       TDE_tdsRect *p_stScreenRect)
{
    TDE_tdxValue     xScaledSpriteW, xScaledSpriteH, xSpriteCenterX, xSpriteCenterY, 
                     xSpriteCornerX, xSpriteCornerY;
    long             lPitchDest, lViewPortW, lViewPortH;                  
    TDE_tdsRect      stDestRect, stClippedDestRect;
    TDE_tdsMemZone   stSource;
    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;
//  clipping value  0->no clipped, 1->clipped to screen rect, 2->clipped to SO clipping rectangle
    char             clipped = 0;
            
    stDestRect.lPitch = lPitchDest = (p_stViewAttrib->lPitch)>>C_TDEDEC;
    lViewPortW = p_stViewAttrib->dwWidth;
    lViewPortH = p_stViewAttrib->dwHeight;
        
// xValues
    xScaledSpriteW = p_stSprite->stDim.xX;      // absolute dimensions
    xScaledSpriteH = p_stSprite->stDim.xY;
    xSpriteCenterX = p_stSuperObject->stModifiedMatrix.stTranslateVertex.xX;
    xSpriteCenterY = p_stSuperObject->stModifiedMatrix.stTranslateVertex.xY;    
    xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW, 2) + 0.5;
    xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH, 2) + 0.5;

// Destination rectangle
    iTDE_vFillsRect(&stDestRect, xSpriteCornerX, xSpriteCornerY, xScaledSpriteW, xScaledSpriteH);
           
    // Out of screen ?
    if ( (long)(stDestRect.tdsSommet[0].xX)>p_stScreenRect->tdsSommet[1].xX) return;
    if ( (long)(stDestRect.tdsSommet[2].xX)<p_stScreenRect->tdsSommet[0].xX) return;
    if ( (long)(stDestRect.tdsSommet[0].xY)>p_stScreenRect->tdsSommet[3].xY) return;
    if ( (long)(stDestRect.tdsSommet[2].xY)<p_stScreenRect->tdsSommet[0].xY) return;

    // Clipped ?
    if ( ( (long)(stDestRect.tdsSommet[0].xX)<p_stScreenRect->tdsSommet[0].xX) ||
         ( (long)(stDestRect.tdsSommet[1].xX)>p_stScreenRect->tdsSommet[1].xX) ||
         ( (long)(stDestRect.tdsSommet[0].xY)<p_stScreenRect->tdsSommet[0].xY) ||
         ( (long)(stDestRect.tdsSommet[3].xY)>p_stScreenRect->tdsSommet[3].xY) )
    {
        clipped = 1;
    }

    if (p_stSuperObject->p_stSOClipRect)
        clipped = 2;

    if (clipped)
    {
        //iTDE_vAdjustScreenRectForClip(&stDestRect, &stClippedDestRect, lViewPortW, lViewPortH);
        if ( clipped == 1)
                iTDE_vAdjustScreenRectToClipRect(&stDestRect, &stClippedDestRect, p_stScreenRect);
        else if ( clipped == 2)
                iTDE_vAdjustScreenRectToClipRect(&stDestRect, &stClippedDestRect, p_stSuperObject->p_stSOClipRect);
                
        stClippedDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);
        
        stSource.p_usPointer = p_stSprite->v_pData +  // recal
        TDE_M_ValueToLong (
        ( TDE_M_ValueToLong(stClippedDestRect.tdsSommet[0].xY) - TDE_M_ValueToLong(stDestRect.tdsSommet[0].xY) )*xScaledSpriteW ) + 
        ( TDE_M_ValueToLong(stClippedDestRect.tdsSommet[0].xX) - TDE_M_ValueToLong(stDestRect.tdsSommet[0].xX) );
          
        stSource.stDim.xX = xScaledSpriteW;
        stSource.stDim.xY = xScaledSpriteH;
        stSource.xMagicColor = p_stSprite->xMagicColor;
   
        if (p_stSprite->c_NZ)
        { iTDE_vBlitClipMemory_NZ(&stSource, &stClippedDestRect); }    
        else
        { iTDE_vBlitClipMemory(&stSource, &stClippedDestRect); }
    }
    else
    {
        stDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);    
        stSource.p_usPointer = (TDE_tdxPixel *)(p_stSprite->v_pData);
        stSource.stDim.xX = xScaledSpriteW;
        stSource.stDim.xY = xScaledSpriteH;
        stSource.xMagicColor = p_stSprite->xMagicColor;

        if (p_stSprite->c_NZ)
        { iTDE_vBlitFastMemory_NZ(&stSource, &stDestRect); }    
        else
        { iTDE_vBlitFastMemory(&stSource, &stDestRect); }        
    }
}

/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vFastDrawMemorySpriteAbsoluteInvert
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Display a sprite stored in memory
 ! ATTENTION ! : The sprite has to be defined with absolute coordinates
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/
void TDE_vFastDrawMemorySpriteAbsoluteInvert(GLD_tdpstViewportAttributes p_stViewAttrib,
                                              TDE_tdsSuperObject *p_stSuperObject,
                                              TDE_tdsRect *p_stScreenRect)
{
    TDE_tdxValue     xScaledSpriteW, xScaledSpriteH, xSpriteCenterX, xSpriteCenterY, 
                     xSpriteCornerX, xSpriteCornerY;
    long             lPitchDest, lViewPortW, lViewPortH;                  
    TDE_tdsRect      stDestRect, stClippedDestRect;
    TDE_tdsMemZone   stSource;
    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;
    char             clipped = 0;
            
    stDestRect.lPitch = lPitchDest = (p_stViewAttrib->lPitch)>>C_TDEDEC;
    lViewPortW = p_stViewAttrib->dwWidth;
    lViewPortH = p_stViewAttrib->dwHeight;
        
// xValues
    xScaledSpriteW = p_stSprite->stDim.xX;      // absolute dimensions
    xScaledSpriteH = p_stSprite->stDim.xY;
    xSpriteCenterX = p_stSuperObject->stModifiedMatrix.stTranslateVertex.xX;
    xSpriteCenterY = p_stSuperObject->stModifiedMatrix.stTranslateVertex.xY;    
    xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW, 2) + 0.5;
    xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH, 2) + 0.5;

// Destination rectangle
/*
    iTDE_vFillsRect(&stDestRect, xSpriteCornerX - xSpriteCenterX, xSpriteCornerY - xSpriteCenterY,
                    xScaledSpriteW, xScaledSpriteH);

    for (si=0; si<4; si++)
    {                
       stDestRect.tdsSommet[si].xX += xSpriteCenterX;
       stDestRect.tdsSommet[si].xY += xSpriteCenterY;       
    }
*/
    iTDE_vFillsRect(&stDestRect, xSpriteCornerX, xSpriteCornerY, xScaledSpriteW, xScaledSpriteH);
           
    // Out of screen ?
    if ( (long)(stDestRect.tdsSommet[0].xX)>p_stScreenRect->tdsSommet[1].xX) return;
    if ( (long)(stDestRect.tdsSommet[2].xX)<p_stScreenRect->tdsSommet[0].xX) return;
    if ( (long)(stDestRect.tdsSommet[0].xY)>p_stScreenRect->tdsSommet[3].xY) return;
    if ( (long)(stDestRect.tdsSommet[2].xY)<p_stScreenRect->tdsSommet[0].xY) return;

    // Clipped ?
    if ( ( (long)(stDestRect.tdsSommet[0].xX)<p_stScreenRect->tdsSommet[0].xX) ||
         ( (long)(stDestRect.tdsSommet[1].xX)>p_stScreenRect->tdsSommet[1].xX) ||
         ( (long)(stDestRect.tdsSommet[0].xY)<p_stScreenRect->tdsSommet[0].xY) ||
         ( (long)(stDestRect.tdsSommet[3].xY)>p_stScreenRect->tdsSommet[3].xY) )
    {
        clipped = 1;
    }
    
    if (p_stSuperObject->p_stSOClipRect)
        clipped = 2;

    if ( clipped == 1 )
    {
        //iTDE_vAdjustScreenRectForClip(&stDestRect, &stClippedDestRect, lViewPortW, lViewPortH);
        if ( clipped == 1)
                iTDE_vAdjustScreenRectToClipRect(&stDestRect, &stClippedDestRect, p_stScreenRect);
        else if ( clipped == 2)
                iTDE_vAdjustScreenRectToClipRect(&stDestRect, &stClippedDestRect, p_stSuperObject->p_stSOClipRect);

        stClippedDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);
        
        stSource.p_usPointer = p_stSprite->v_pData +  // recal
        TDE_M_ValueToLong (
        ( TDE_M_ValueToLong(stClippedDestRect.tdsSommet[0].xY) - TDE_M_ValueToLong(stDestRect.tdsSommet[0].xY) )*xScaledSpriteW ) + 
        ( TDE_M_ValueToLong(stClippedDestRect.tdsSommet[0].xX) - TDE_M_ValueToLong(stDestRect.tdsSommet[0].xX) );
          
        stSource.stDim.xX = xScaledSpriteW;
        stSource.stDim.xY = xScaledSpriteH;
        stSource.xMagicColor = p_stSprite->xMagicColor;
   
        if (p_stSprite->c_NZ)
        { iTDE_vBlitClipMemory_Invert_NZ(&stSource, &stClippedDestRect); }    
        else
        { iTDE_vBlitClipMemory_Invert(&stSource, &stClippedDestRect); }
    }
    else
    {
        stDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);    
        stSource.p_usPointer = (TDE_tdxPixel *)(p_stSprite->v_pData);
        stSource.stDim.xX = xScaledSpriteW;
        stSource.stDim.xY = xScaledSpriteH;
        stSource.xMagicColor = p_stSprite->xMagicColor;

        if (p_stSprite->c_NZ)
        { iTDE_vBlitFastMemory_Invert_NZ(&stSource, &stDestRect); }    
        else
        { iTDE_vBlitFastMemory_Invert(&stSource, &stDestRect); }        
    }
}


void TDE_vFastDrawBackGround(GLD_tdpstViewportAttributes p_stViewAttrib,
                             TDE_tdsSuperObject *p_stSuperObject)
{
    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;
    TDE_tdxPixel     *src, *dest;
            
    dest = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);
    src = p_stSprite->v_pData;
        
    //iTDE_vBackground((long *)src, (long *)dest);
}


/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vDrawSuperObjectClipped16
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Display a super object with clipping (for sprites)
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/

void TDE_vDrawSuperObjectClipped16(GLD_tdpstViewportAttributes p_stViewAttrib,
                                    TDE_tdsSuperObject *p_stSuperObject)
{
    TDE_tdxValue     xScaledSpriteW, xScaledSpriteH, xSpriteCenterX, xSpriteCenterY, 
                     xSpriteCornerX, xSpriteCornerY, xSourceCornerX, xSourceCornerY,
                     xScaledSourceW, xScaledSourceH;                
    long            lPitchDest, lPitchSrc, lViewPortW, lViewPortH;                                        
    short           si;    
    TDE_tdsRect      stSrcRect, stDestRect, stClippedDestRect,
                     stSrcFlippedRect, stSrcClippedRect;
    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;
    
    stSrcRect.lPitch =  lPitchSrc  = ((long)(p_stSprite->stPicture.xSrcPitch))>>C_TDEDEC; 
    stDestRect.lPitch = lPitchDest = (p_stViewAttrib->lPitch)>>C_TDEDEC;
    lViewPortW = p_stViewAttrib->dwWidth;
    lViewPortH = p_stViewAttrib->dwHeight;
        
    // xValues
    xScaledSpriteW = TDE_M_Mul(lViewPortW , p_stSprite->stDim.xX);
    xScaledSpriteH = TDE_M_Mul(lViewPortH , p_stSprite->stDim.xY);    
    xSpriteCenterX = TDE_M_Mul(lViewPortW , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xX);
    xSpriteCenterY = TDE_M_Mul(lViewPortH , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xY);
    xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW,2);
    xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH,2);
    xSourceCornerX = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stSourceOrigin.xX);
    xSourceCornerY = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stSourceOrigin.xY);    
    xScaledSourceW = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stDim.xX);
    xScaledSourceH = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stDim.xY);

    // Screen rectangle
    iTDE_vFillsRect(&stDestRect, xSpriteCornerX - xSpriteCenterX, xSpriteCornerY - xSpriteCenterY,
                                 xScaledSpriteW, xScaledSpriteH);

    // Transformation    
    for ( si=0; si<4; si++ )
    {                
       TDE_vMulMatrixByVertex(&(p_stSuperObject->stModifiedMatrix.a4_xS), &(stDestRect.tdsSommet[si]), &(stDestRect.tdsSommet[si]));
       stDestRect.tdsSommet[si].xX += xSpriteCenterX;
       stDestRect.tdsSommet[si].xY += xSpriteCenterY;
    }

    // Out of screen
    if ( (long)(stDestRect.tdsSommet[0].xX)>lViewPortW ) return;
    if ( (long)(stDestRect.tdsSommet[2].xX)<0 )          return;
    if ( (long)(stDestRect.tdsSommet[0].xY)>lViewPortH ) return;
    if ( (long)(stDestRect.tdsSommet[2].xY)<0 )          return;
    
    // Adjust destination rectangle for clipping
    iTDE_vAdjustScreenRectForClip(&stDestRect, &stClippedDestRect, lViewPortW, lViewPortH);
    
    stClippedDestRect.p_usPointer = (TDE_tdxPixel *)(p_stViewAttrib->p_cVirtualScreen);
    
    // Source rectangle
    iTDE_vFillsRect(&stSrcRect, xSourceCornerX, xSourceCornerY, xScaledSourceW, xScaledSourceH);
    stSrcRect.p_usPointer = (TDE_tdxPixel *)(p_stSprite->stPicture.lp_Data);

    // Adjust source rectangle for flip
    iTDE_vAdjustRectToFlip(&stSrcRect, &stSrcFlippedRect, p_stSprite->cFlip);

    // Adjust source rectangle for clip
    iTDE_vAdjustSourceRectForClip(&stDestRect, &stSrcFlippedRect, &stSrcClippedRect, lViewPortW, lViewPortH);

    // Drawing loop        
    if ( !p_stSprite->cSemiTransparent )
         { iTDE_vBlit(&stSrcClippedRect, &stClippedDestRect); }
    else         
         { iTDE_vBlit_Transparency(&stSrcClippedRect, &stClippedDestRect, p_stSprite->alpha); }
}


/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vCalculateIntermediateVertex
 VERSION : 2.0 / Valérie
                   1.0 / Franck

 AIM : Calculate the clipped vertex between two points
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/

void TDE_vCalculateIntermediateVertex(TDE_tdsClippedVertex1616 *Result_Point, TDE_tdsClippedVertex1616 *Point1, TDE_tdsClippedVertex1616 *Point2, TDE_tdl1616 lValue1, TDE_tdl1616 lValue2, TDE_tdl1616 lInterValue)
{
  TDE_tdl1616 lInvert;
  
  lInvert = TDE_DIV ( (lInterValue-lValue2) , (lValue1-lValue2) );
  Result_Point->Point.lX = Point2->Point.lX + TDE_MUL( (Point1->Point.lX) - (Point2->Point.lX), lInvert ) ;
  Result_Point->Point.lY = Point2->Point.lY + TDE_MUL( (Point1->Point.lY) - (Point2->Point.lY), lInvert ) ;
  Result_Point->TexPoint.lX = Point2->TexPoint.lX + TDE_MUL( Point1->TexPoint.lX - Point2->TexPoint.lX, lInvert );
  Result_Point->TexPoint.lY = Point2->TexPoint.lY + TDE_MUL( Point1->TexPoint.lY - Point2->TexPoint.lY, lInvert );
}


/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_lClipPolygon
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Clip a polygon
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/

long TDE_cClipPolygon(char cNB_SOMMETS, TDE_tdsClippedVertex1616 *p_stClipped_Line, long lWidth, long lHeight)
{
  char cNB_SOMMETS2, cIndix, cVertexIndix, cClipped_NB_Sommets, cOver;
  TDE_tdl1616 lYemin1616, lYemax1616, lXemin1616, lXemax1616;
  TDE_tdsClippedVertex1616 *p_stCLineInter1, *p_stCLineInter2, *p_stCLine2Inter, p_stClipped_Line_2[20];
  
  lYemin1616 = 1<<16;
  lYemax1616 = (lHeight-1)<<16;
  lXemin1616 = 1<<16;
  lXemax1616 = (lWidth-1)<<16;  
  
// Top cutting
  cVertexIndix = (char)(cNB_SOMMETS-1);
  cClipped_NB_Sommets = 0;

  p_stCLineInter2 = &p_stClipped_Line[cVertexIndix];
  p_stCLineInter1 = &p_stClipped_Line[0];
  p_stCLine2Inter = &p_stClipped_Line_2[0];
  for (cIndix=0; cIndix<cNB_SOMMETS; cIndix++)
  {
     cOver = 0;
     if (p_stCLineInter1->Point.lY>=lYemin1616) cOver = 1;
     if (p_stCLineInter2->Point.lY>=lYemin1616) cOver |= 2;
     switch (cOver&3) {
          case 3:
                 *(p_stCLine2Inter++) = *p_stCLineInter1;
                 cClipped_NB_Sommets++;
                 break;
          case 1:
                TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter1, p_stCLineInter2, p_stCLineInter1->Point.lY, p_stCLineInter2->Point.lY, lYemin1616);
                *(p_stCLine2Inter++) = *p_stCLineInter1;
                cClipped_NB_Sommets += 2;
                break;
          case 2:
                TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter2, p_stCLineInter1, p_stCLineInter2->Point.lY, p_stCLineInter1->Point.lY, lYemin1616);
                cClipped_NB_Sommets++;
                break;
      } 
      p_stCLineInter2 = p_stCLineInter1;
      p_stCLineInter1++;
  }
  if (cClipped_NB_Sommets<2) return(0);
  cNB_SOMMETS2 = cClipped_NB_Sommets;

// Bottom cutting
  cVertexIndix = (char)(cNB_SOMMETS2-1);
  cClipped_NB_Sommets  = 0;
  p_stCLineInter2 = &p_stClipped_Line_2[cVertexIndix];
  p_stCLineInter1 = &p_stClipped_Line_2[0];
  p_stCLine2Inter = &p_stClipped_Line[0];
  for (cIndix=0; cIndix<cNB_SOMMETS2; cIndix++)
  {
     cOver = 0;
     if (p_stCLineInter1->Point.lY<=lYemax1616) cOver = 1;
     if (p_stCLineInter2->Point.lY<=lYemax1616) cOver |= 2;
     switch (cOver&3) {
              case 3:        
                    *(p_stCLine2Inter++) = *p_stCLineInter1;
                    cClipped_NB_Sommets++;
                    break;

              case 1:
                    TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter1, p_stCLineInter2, p_stCLineInter1->Point.lY, p_stCLineInter2->Point.lY, lYemax1616);
                    *(p_stCLine2Inter++) = *p_stCLineInter1;
                    cClipped_NB_Sommets += 2;
                    break;
 
              case 2:
                    TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter2, p_stCLineInter1, p_stCLineInter2->Point.lY, p_stCLineInter1->Point.lY, lYemax1616);
                    cClipped_NB_Sommets++;
                    break;
      } 
      p_stCLineInter2 = p_stCLineInter1;
      p_stCLineInter1++;
   } 
   if (cClipped_NB_Sommets<2) return(0);
   cNB_SOMMETS = cClipped_NB_Sommets;

// Left cutting

   cVertexIndix= (char)(cNB_SOMMETS-1);
   cClipped_NB_Sommets = 0;
   p_stCLineInter2 = &p_stClipped_Line[cVertexIndix];
   p_stCLineInter1 = &p_stClipped_Line[0];
   p_stCLine2Inter = &p_stClipped_Line_2[0];
   for (cIndix=0; cIndix<cNB_SOMMETS; cIndix++)
   {
       cOver = 0;
       if (p_stCLineInter1->Point.lX>=lXemin1616) cOver = 1;
       if (p_stCLineInter2->Point.lX>=lXemin1616) cOver |= 2;
       switch (cOver&3) {
               case 3:
                    *(p_stCLine2Inter++) = *p_stCLineInter1;
                    cClipped_NB_Sommets++;
                    break;
               case 1:
                    TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter1, p_stCLineInter2, p_stCLineInter1->Point.lX, p_stCLineInter2->Point.lX, lXemin1616);
                    *(p_stCLine2Inter++) = *p_stCLineInter1;
                    cClipped_NB_Sommets += 2;
                    break;
 
               case 2:
                    TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter2, p_stCLineInter1, p_stCLineInter2->Point.lX, p_stCLineInter1->Point.lX, lXemin1616);
                    cClipped_NB_Sommets++;
                    break;
        }
        p_stCLineInter2 = p_stCLineInter1;
        p_stCLineInter1++;
   }
   if (cClipped_NB_Sommets<2) return(0);

// Right cutting

   cNB_SOMMETS2 = cClipped_NB_Sommets;
   cVertexIndix = (char)(cNB_SOMMETS2-1);
   cClipped_NB_Sommets = 0;
   p_stCLineInter2 = &p_stClipped_Line_2[cVertexIndix];
   p_stCLineInter1 = &p_stClipped_Line_2[0];
   p_stCLine2Inter = p_stClipped_Line;
   for (cIndix=0; cIndix<cNB_SOMMETS2; cIndix++)
   {
         cOver = 0;
         if (p_stCLineInter1->Point.lX<=lXemax1616) cOver = 1;
         if (p_stCLineInter2->Point.lX<=lXemax1616) cOver |= 2;
         switch (cOver&3) {
               case 3:
                   *(p_stCLine2Inter++) = *p_stCLineInter1;
                   cClipped_NB_Sommets++;
                   break;
               case 1:
                   TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter1, p_stCLineInter2, p_stCLineInter1->Point.lX, p_stCLineInter2->Point.lX, lXemax1616);
                   *(p_stCLine2Inter++) = *p_stCLineInter1;
                   cClipped_NB_Sommets += 2;
                   break;
               case 2:
                   TDE_vCalculateIntermediateVertex(p_stCLine2Inter++, p_stCLineInter2, p_stCLineInter1, p_stCLineInter2->Point.lX, p_stCLineInter1->Point.lX, lXemax1616);
                   cClipped_NB_Sommets++;
                   break;
         } 
         p_stCLineInter2 = p_stCLineInter1;
         p_stCLineInter1++;
    }

    if (cClipped_NB_Sommets<2) return(0);
    return(cClipped_NB_Sommets);
}


/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vFillTableMM
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Fill the Min-Max Table
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/

void TDE_vFillTableMM(long lStart, long lLenght, long lColumn, TDE_tdl1616 lValue1, TDE_tdl1616 lValue2)
{
   TDE_tdl1616 *p_MMStart, *p_MMEnd;
   TDE_tdl1616 lVinc;
   
   if (lValue2 != lValue1)
   {
       lVinc = TDE_DIV( lValue2-lValue1 , (lLenght<<16) );
       p_MMStart = &a_lTableMM[lStart][lColumn];
       p_MMEnd = p_MMStart + (lLenght<<3);
       for (;p_MMStart<p_MMEnd; p_MMStart=p_MMStart+8, lValue1 += lVinc)
            *p_MMStart = lValue1;
   }
   else
   {
       p_MMStart = &a_lTableMM[lStart][lColumn];
       p_MMEnd = p_MMStart+(lLenght<<3);
       for (;p_MMStart<p_MMEnd; p_MMStart = p_MMStart+8)
            *p_MMStart = lValue1;
   }         
}


void TDE_vDrawSuperObjectRotated16(GLD_tdpstViewportAttributes p_stViewAttrib,
                                    TDE_tdsSuperObject *p_stSuperObject)
{
    TDE_tdxValue      xW, xH, xXc, xYc, xXs, xYs, xWs, xHs, xX, xY;
    TDE_tdl1616       lXg, lXd, lUg, lUd, lVg, lVd, ldU, ldV, ldX,
                      ldE, lF, ldF, ldY;
    short            si;    
    long             lPitSrc, lPitDest, lgW, lgH,
                      lNBSommets, lYmin, lYmax, *T_H, lMiddle;
    TDE_tdxPixel     *p_usDest, *p_usDestEnd, *p_usDestSave, *p_usOfs, *p_usL,
                      c, usSpritePixel, usBackPixel;     
    TDE_tdsClippedVertex1616  Polygon[8], *Ptr1, *Ptr2;
    TDE_tdsClippedVertex      xPolygon[8];

    TDE_tdsSprite    *p_stSprite = p_stSuperObject->p_stSprite;

    // Variables for alpha-transparency
    short sBlueMask = 0x001F;   // 0000 0000 0001 1111  -> obtain blue component
    short sGreenMask = 0x07E0;  // 0000 0111 1110 0000  -> obtain green component
//    short sRedMask  = 0xF800;   // 1111 1000 0000 0000  -> obtain red component
    short sB, sG, sR;
    char cIndix1, cIndix2;
    unsigned char *p_cAcc15, *p_cAcc25, *p_cAcc16, *p_cAcc26;
    
    lPitSrc  = ((long)(p_stSprite->stPicture.xSrcPitch))>>C_TDEDEC; 
    lPitDest = (p_stViewAttrib->lPitch)>>C_TDEDEC;
    lgW      = p_stViewAttrib->dwWidth;
    lgH      = p_stViewAttrib->dwHeight;
        
// xValues
    xW       = TDE_M_Mul(lgW , p_stSprite->stDim.xX);
    xH       = TDE_M_Mul(lgH , p_stSprite->stDim.xY);    
    xXc      = TDE_M_Mul(lgW , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xX);
    xYc      = TDE_M_Mul(lgH , p_stSuperObject->stModifiedMatrix.stTranslateVertex.xY);
    xXs      = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stSourceOrigin.xX);
    xYs      = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stSourceOrigin.xY);
    xWs      = TDE_M_Mul(p_stSprite->stPicture.xWidth  , p_stSprite->stDim.xX);
    xHs      = TDE_M_Mul(p_stSprite->stPicture.xHeight , p_stSprite->stDim.xY);
    xX       = xXc - TDE_M_Div(xW,2);
    xY       = xYc - TDE_M_Div(xH,2);

    p_usOfs   = p_usL = (TDE_tdxPixel *)(p_stSprite->stPicture.lp_Data);
    p_usDest  = (TDE_tdxPixel *)p_stViewAttrib->p_cVirtualScreen;
    
    if (((xX+xW)<=1.0)||(xX>=lgW)) return;
    if (((xY+xH)<=1.0)||(xY>=lgH)) return;
    
    xPolygon[0].Point.xX = xX-xXc;      
    xPolygon[0].Point.xY = xY-xYc;      

    xPolygon[1].Point.xX = xX+xW-xXc;   
    xPolygon[1].Point.xY = xY-xYc;       

    xPolygon[2].Point.xX = xX+xW-xXc;  
    xPolygon[2].Point.xY = xY+xH-xYc;  
    
    xPolygon[3].Point.xX = xX-xXc;  
    xPolygon[3].Point.xY = xY+xH-xYc;
    
    for (si=0; si<4; si++)
    {                
       TDE_vMulMatrixByVertex(&(p_stSuperObject->stModifiedMatrix.a4_xRxS), &xPolygon[si].Point, &xPolygon[si].Point);
       xPolygon[si].Point.xX += xXc;
       xPolygon[si].Point.xY += xYc;       
    }
               
    xPolygon[0].TexPoint.xX = xPolygon[3].TexPoint.xX = xXs;
    xPolygon[1].TexPoint.xX = xPolygon[2].TexPoint.xX = xXs+xWs;
    
    xPolygon[0].TexPoint.xY = xPolygon[1].TexPoint.xY = xYs;
    xPolygon[2].TexPoint.xY = xPolygon[3].TexPoint.xY = xYs+xHs;

// xPolygon -> Polygon
   for (si=0; si<4; si++)
   {
       Polygon[si].Point.lX = TDE_M_ValueTo1616(xPolygon[si].Point.xX);
       Polygon[si].Point.lY = TDE_M_ValueTo1616(xPolygon[si].Point.xY);
       Polygon[si].TexPoint.lX = TDE_M_ValueTo1616(xPolygon[si].TexPoint.xX);
       Polygon[si].TexPoint.lY = TDE_M_ValueTo1616(xPolygon[si].TexPoint.xY);              
   }
    
// Clip
   lNBSommets = TDE_cClipPolygon(4, Polygon, lgW, lgH);

// 16:16 -> int
    for (si=0; si<lNBSommets; si++)
        Polygon[si].Point.lY>>=16;
           
// Fills min-max table    
    if (lNBSommets>2)
    {        
          Ptr1 = &Polygon[0];
          Ptr2 = &Polygon[lNBSommets-1];
          lYmin = Ptr2->Point.lY;
          lYmax = Ptr2->Point.lY;
          for (si=0; si<lNBSommets; si++)
          {
                if (Ptr1->Point.lY<lYmin) lYmin = Ptr1->Point.lY;
                if (Ptr1->Point.lY>lYmax) lYmax = Ptr1->Point.lY;
                if (Ptr2->Point.lY<Ptr1->Point.lY)
                { // Right
                        TDE_vFillTableMM(Ptr2->Point.lY, Ptr1->Point.lY-Ptr2->Point.lY, 1, Ptr2->Point.lX, Ptr1->Point.lX);                        
                        TDE_vFillTableMM(Ptr2->Point.lY, Ptr1->Point.lY-Ptr2->Point.lY, 4, Ptr2->TexPoint.lX, Ptr1->TexPoint.lX);
                        TDE_vFillTableMM(Ptr2->Point.lY, Ptr1->Point.lY-Ptr2->Point.lY, 5, Ptr2->TexPoint.lY, Ptr1->TexPoint.lY);
                }
                else if (Ptr2->Point.lY>Ptr1->Point.lY)
                { // Left
                        TDE_vFillTableMM(Ptr1->Point.lY, Ptr2->Point.lY-Ptr1->Point.lY, 0, (Ptr1->Point.lX), (Ptr2->Point.lX));                        
                        TDE_vFillTableMM(Ptr1->Point.lY, Ptr2->Point.lY-Ptr1->Point.lY, 2, (Ptr1->TexPoint.lX), (Ptr2->TexPoint.lX));
                        TDE_vFillTableMM(Ptr1->Point.lY, Ptr2->Point.lY-Ptr1->Point.lY, 3, (Ptr1->TexPoint.lY), (Ptr2->TexPoint.lY));
                }
                Ptr2=Ptr1;
                Ptr1++;
          }
    }

// Is the sprite out of screen (Y) ?
    if ((lYmin>=(lgH-1))||(lYmax<=1)) return;

// Increments calculation
    lMiddle = lYmin+((lYmax-lYmin)>>1);
    if ((lMiddle<0)||(lMiddle>768)) return;              // debug
    T_H = &a_lTableMM[lMiddle][0];
    ldX = *(T_H+1) - *(T_H);
    lUg = *(T_H+2);
    lVg = *(T_H+3);
    lUd = *(T_H+4);
    lVd = *(T_H+5);
               
    if (ldX>0)
      {
        ldU = TDE_DIV((lUd-lUg),ldX);
        ldV = TDE_DIV((lVd-lVg),ldX);         
      }
    else return; 

    ldE = lPitSrc*(ldV>>16)+(ldU>>16);
    ldF = ((ldV>>1)&0x7FFF)+((ldU<<15)&0x7FFF0000);
    T_H = &a_lTableMM[lYmin][0];
    p_usDest += lYmin*lPitDest;
    ldY = lYmax-lYmin;
        
// Main loop

    if (!p_stSprite->cSemiTransparent)
    {
        // No semi-transparency
        for (si=0; si<ldY; si++,T_H+=8)
        {        
            lXg  = *(T_H)>>16;
            lXd  = *(T_H+1)>>16;
            lUg  = *(T_H+2);
            lVg  = *(T_H+3);                       
            lF   = ((lVg>>1)&0x7FFF)+((lUg<<15)&0x7FFF0000);
            p_usOfs  = p_usL + lPitSrc*(lVg>>16)+(lUg>>16);
            p_usDestSave = p_usDest;
            p_usDestEnd  = p_usDest+lXd;        

            for (p_usDest=p_usDest+lXg; p_usDest<p_usDestEnd; p_usDest++)
            {
                //if (p_cOfs>p_cL)                    // debug          
                c = *p_usOfs;       
                if (c>0)
                  *p_usDest = c;            
                lF += ldF;
                p_usOfs += ldE;
                if (lF&0x8000) {lF&=0xFFFF7FFF; p_usOfs+=lPitSrc; }
                if (lF&0x80000000) {lF&=0x7FFFFFFF; p_usOfs++; }
            }
                
            p_usDest = p_usDestSave + lPitDest;
        }
        return;
    }
    else
    {
        cIndix1 = ((char)(p_stSprite->alpha*64))&0x3F;
        cIndix2 = 63-cIndix1;
        p_cAcc15 = &(a_cTransparencyTable5[cIndix1][0]);
        p_cAcc25 = &(a_cTransparencyTable5[cIndix2][0]);
        p_cAcc16 = &(a_cTransparencyTable6[cIndix1][0]);
        p_cAcc26 = &(a_cTransparencyTable6[cIndix2][0]);
        
        // semi-transparency
        for (si=0; si<ldY; si++,T_H+=8)
        {        
             lXg  = *(T_H)>>16;
             lXd  = *(T_H+1)>>16;
             lUg  = *(T_H+2);
             lVg  = *(T_H+3);                       
             lF   = ((lVg>>1)&0x7FFF)+((lUg<<15)&0x7FFF0000);
             p_usOfs  = p_usL + lPitSrc*(lVg>>16)+(lUg>>16);
             p_usDestSave = p_usDest;
             p_usDestEnd  = p_usDest + lXd;

             
             for (p_usDest=p_usDest+lXg; p_usDest<p_usDestEnd; p_usDest++)
             {                                    
                  usSpritePixel = *p_usOfs;            
                  if (usSpritePixel>0)
                  {
                     usBackPixel = *p_usDest;                
                     sB = *(p_cAcc15 + (usBackPixel & sBlueMask)) + *(p_cAcc25+ (usSpritePixel & sBlueMask));
                     sG = *(p_cAcc16 + ((usBackPixel & sGreenMask)>>5)) + *(p_cAcc26 + ((usSpritePixel & sGreenMask)>>5));
                     sR = *(p_cAcc15 + (usBackPixel>>11)) + *(p_cAcc25 + (usSpritePixel>>11));                
                     *p_usDest = sB+(sG<<5)+(sR<<11);                               
                  }
                  lF += ldF;
                  p_usOfs += ldE;
                  if (lF&0x8000) {lF&=0xFFFF7FFF; p_usOfs+=lPitSrc; }
                  if (lF&0x80000000) {lF&=0x7FFFFFFF; p_usOfs++; }
             }        
             p_usDest = p_usDestSave + lPitDest;
                          
        }
    } // if (!p_stSprite->cSemiTransparent ....)     
}

void TDE_vResetTable()
{
        short si, sj;

        for (si=0; si<768; si++)
        {
                for (sj=0; sj<8; sj++) a_lTableMM[si][sj] = 0;
        }
}


void TDE_vSendObjectsToViewPort(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObject, TDE_p_stSuperObject *ZList)
{
    //TDE_tdsSuperObject *p_stSuperObjectTemp;    

// Reset matrices stack (!)        
    ResetMatrixStack((TDE_tdsCamera *)(p_stViewAttrib->p_vSpecificToXD));
// Init Z list    
    TDE_vInitZList(ZList);
// Rebuild all SuperObjects matrices
    TDE_vCreateSuperObjectDescendancyMatrices(p_stSuperObject);
// Build Z list    
    TDE_vBuildHierarchy(p_stSuperObject, ZList);
}

/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**
 NAME : TDE_vSendListToViewPort
 VERSION : 2.0 / Valérie
           1.0 / Franck

 AIM : Send Z liste to a viewport
 Disposable functions :
  TDE_vDrawSuperObject16(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObjet);
  TDE_vDrawSuperObjectFast16(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObjet);
  TDE_vDrawMemSprite_Abs_16(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObjet);
  TDE_vDrawSuperObjectRotated16(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObjet);
  TDE_vDrawSuperObjectClipped16(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObjet);  
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/
void TDE_vSendListToViewPort(GLD_tdpstViewportAttributes p_stViewAttrib, TDE_p_stSuperObject *ZList, TDE_tdsRect *stClipScreenRect, BOOL bViewPortLocked)
{
    TDE_tdsSuperObject *p_stSuperObjectTemp;    
    short  si;
    
// Draw ZList
    if (bViewPortLocked)
    {
        // Viewport is locked : draw everything but True Type text
        for (si=0; si<TDE_kMAXPRIORITY; si++)
        {
            if (ZList[si]!=NULL)
                for (p_stSuperObjectTemp = ZList[si]; p_stSuperObjectTemp != NULL; p_stSuperObjectTemp = p_stSuperObjectTemp->p_stNextZList)
                {
                    if (p_stSuperObjectTemp->p_vPointer != NULL)
                    {
                        switch (p_stSuperObjectTemp->eType)
                        {
                            case TDE_eOT_SPRITE:
                                TDE_vFastDrawMemorySpriteAbsolute(p_stViewAttrib, p_stSuperObjectTemp, stClipScreenRect);
                                break;
                            case TDE_eOT_TEXTBOX:
                                TDE_vDrawTextInABox(p_stViewAttrib, p_stSuperObjectTemp, TRUE);
                                break;
                            case TDE_eOT_LINE:
                                TDE_vDrawSuperObjectLineAbs(p_stViewAttrib, p_stSuperObjectTemp);
                                break;    
                            case TDE_eOT_EMPTY:
                                break;
                        }
                    }
                }
        }
    }
    else
    {
        // Viewport is not locked : draw nothing but True Type text
        for (si=0; si<TDE_kMAXPRIORITY; si++)
        {
            if (ZList[si]!=NULL)
                for (p_stSuperObjectTemp = ZList[si]; p_stSuperObjectTemp != NULL; p_stSuperObjectTemp = p_stSuperObjectTemp->p_stNextZList)
                {
                    if (p_stSuperObjectTemp->p_vPointer != NULL)
                    {
                        switch (p_stSuperObjectTemp->eType)
                        {
                            case TDE_eOT_TEXTBOX:
                                TDE_vDrawTextInABox(p_stViewAttrib, p_stSuperObjectTemp, FALSE);
                                break;
                            case TDE_eOT_EMPTY:
                                break;
                        }
                    }
                }
        }
    }
}
