/****************************************************************************/
/*                                                                          */
/* SAMPDECO.C: Sample Codec Decompression/Display Routines.                 */
/*             Your routines will replace these.  For speed, your           */
/*             routines should be written in 32-bit assembly.               */
/*                                                                          */
/* Copyright (c) IBM Corporation 1991,1992,1993        All Rights Reserved  */
/*                                                                          */
/****************************************************************************/

#include <os2.h>

/* This is an external declaration to the color conversion table that we    */
/* statically defined in the SAMPGDAT.C global process data section.        */
extern BYTE aColorConv[512];



/****************************************************************************/
/*                                                                          */
/* SUBROUTINE NAME: DecodeAndDisplayToRGB16.                                */
/*     This procedure is the main decode and display routine.  It decodes   */
/*     and displays one 8x8 at a time in 8x8 raster scan order.  Many       */
/*     algorithms use blocks as minimum encoding units for their advantages */
/*     in local commonality.  Here we also check for clipping on a block    */
/*     basis saving more computational resources for decoding.  Note that   */
/*     8x8 clipping my leave artifacts along clipped regions that don't     */
/*     exactly fall on 8x8 boundries.  Note the use of the image width      */
/*     and height counters as an offset into the clipping mask.             */
/*     In SAMPMAIN.C we've defined a negative output width as meaning       */
/*     decode upsidedown (i.e. the screen is in 16-color mode, the          */
/*     video device driver you're using doesn't have the speed enhancements,*/
/*     or your system is configured such that the video card has no or an   */
/*     unusable aperture set up).                                           */
/*                                                                          */
/****************************************************************************/

ULONG DecodeAndDisplayToRGB16 (
         PBYTE  *ppbCompressedData,   /* Pointer to pointer to coded frame. */
         PBYTE  pbDestinationAddr,    /* Destin. address of decoded frame.  */
         PULONG pulCounters,          /* Pointer to counters for decode.    */
         ULONG  ulWidth,              /* Width of output frame.             */
         ULONG  ulHeight,             /* Height of output frame.            */
         LONG   lOutputWidth,         /* Width of screen in * BYTES *.      */
         ULONG  ul8x8RowsToDisplay,   /* Number of 8x8 block rows to decode.*/
         PBYTE  pbClipMask )          /* Pointer to the 8x8 block clip mask.*/
   {
   register PBYTE pbData= *ppbCompressedData;
   register PBYTE pbScreen= pbDestinationAddr;
   ULONG    ulCounter= *pulCounters;
   ULONG    ulBlockY;

   /* If lOutputWidth is negative, move the output pointer to the bottom    */
   /* of the display plane (so we decode upside-down).                      */
   if ( lOutputWidth < 0 )
      pbScreen-= lOutputWidth * ( ul8x8RowsToDisplay << 3 );

   /* If the counters are zero, then this is the first call to the decoder  */
   /* for this frame and we need to initialize them.                        */
   if ( !ulCounter )
      ulCounter= ( ulHeight >> 3 ) << 8;

   /* Decode the image one 8x8 block at a time.                             */
   do {
      ulCounter+= ulWidth >> 3;
      do {
         /* Check the clipping mask, if it's non-zero, we don't display.    */
         if ( *(pbClipMask + ulCounter) )
            {
            /* Just move the output pointer to the next 8x8 block.          */
            pbScreen+= 16;
            pbData+= 64;
            }

         else
            {
            /* Display the 8x8 block.                                       */
            for ( ulBlockY=8; ulBlockY--; )
               {
               /* Output a 1x8 line of pixels through a conversion to RGB16.*/
               *(PUSHORT)pbScreen= * ( (PUSHORT)aColorConv + *pbData );
               *(PUSHORT)(pbScreen+2)= * ( (PUSHORT)aColorConv + *(pbData+1) );
               *(PUSHORT)(pbScreen+4)= * ( (PUSHORT)aColorConv + *(pbData+2) );
               *(PUSHORT)(pbScreen+6)= * ( (PUSHORT)aColorConv + *(pbData+3) );
               *(PUSHORT)(pbScreen+8)= * ( (PUSHORT)aColorConv + *(pbData+4) );
               *(PUSHORT)(pbScreen+10)= * ( (PUSHORT)aColorConv + *(pbData+5) );
               *(PUSHORT)(pbScreen+12)= * ( (PUSHORT)aColorConv + *(pbData+6) );
               *(PUSHORT)(pbScreen+14)= * ( (PUSHORT)aColorConv + *(pbData+7) );
               pbScreen+= lOutputWidth;
               pbData+= 8;
               }

            /* Reset output address to the beginning of the next block.     */
            pbScreen-= (lOutputWidth << 3) - 16;
            }
         }
      while ( --ulCounter & 0xff );

      /* Reset output address to the beginning of the next line.            */
      pbScreen+= (lOutputWidth << 3) - (ulWidth << 1);

      /* Decrement the 8x8 row counter.                                     */
      ulCounter-= 0x0100;
      }
   while ( ulCounter && --ul8x8RowsToDisplay );

   /* Remember, in multiple aperture calls (SVGA systems and the like),     */
   /* we will not be asked to decode the entire image (ulRowsToDisplay).    */
   /* Therefore, we need to save where we where in the compressed data.     */
   *ppbCompressedData= pbData;
   *pulCounters= ulCounter;

   /* No error found (although we're not detecting them in this sample).    */
   return 0;
   }




/****************************************************************************/
/*                                                                          */
/* SUBROUTINE NAME: DecodeAndDisplayToPalette.                              */
/*     This procedure is no different that the above procedure excepting    */
/*     that the output pointer arithmetic is in bytes rather than words     */
/*     and the color table has different contents (8 bit color, not 16).    */
/*     Also, the 8 bit color display routine is used for the 4-bit color    */
/*     decoder (16 color mode) so a 4-bit routine is not needed.            */
/*                                                                          */
/****************************************************************************/

ULONG DecodeAndDisplayToPalette ( PBYTE *ppbCompressedData, PBYTE pbDestAddr,
           PULONG pulCounters, ULONG ulWidth, ULONG ulHeight,
           LONG lOutputWidth, ULONG ul8x8RowsToDisplay, PBYTE pbClipMask )
   {
   register PBYTE pbData= *ppbCompressedData;
   register PBYTE pbScreen= pbDestAddr;
   ULONG    ulCounter= *pulCounters;
   ULONG    ulBlockY;

   /* If lOutputWidth is negative, move the output pointer to the bottom    */
   /* of the display plane (so we decode upside-down).                      */
   if ( lOutputWidth < 0 )
      pbScreen-= lOutputWidth * ( ul8x8RowsToDisplay << 3 );

   /* If the counters are zero, then this is the first call to the decoder  */
   /* for this frame and we need to initialize them.                        */
   if ( !ulCounter )
      ulCounter= ( ulHeight >> 3 ) << 8;

   /* Decode the image one 8x8 block at a time.                             */
   do {
      ulCounter+= ulWidth >> 3;
      do {
         /* Check the clipping mask, if it's non-zero, we don't display.    */
         if ( *(pbClipMask + ulCounter) )
            {
            /* Just move the output pointer to the next 8x8 block.          */
            pbScreen+= 8;
            pbData+= 64;
            }

         else
            {
            /* Display the 8x8 block.                                       */
            for ( ulBlockY=8; ulBlockY--; )
               {
               /* Output a 1x8 line of pixels through a conversion to RGB16.*/
               *pbScreen= * ( (PBYTE)aColorConv + *pbData );
               *(pbScreen+1)= * ( (PBYTE)aColorConv + *(pbData+1) );
               *(pbScreen+2)= * ( (PBYTE)aColorConv + *(pbData+2) );
               *(pbScreen+3)= * ( (PBYTE)aColorConv + *(pbData+3) );
               *(pbScreen+4)= * ( (PBYTE)aColorConv + *(pbData+4) );
               *(pbScreen+5)= * ( (PBYTE)aColorConv + *(pbData+5) );
               *(pbScreen+6)= * ( (PBYTE)aColorConv + *(pbData+6) );
               *(pbScreen+7)= * ( (PBYTE)aColorConv + *(pbData+7) );
               pbScreen+= lOutputWidth;
               pbData+= 8;
               }

            /* Reset output address to the beginning of the next block.     */
            pbScreen-= (lOutputWidth << 3) - 8;
            }
         }
      while ( --ulCounter & 0xff );

      /* Reset output address to the beginning of the next line.            */
      pbScreen+= (lOutputWidth << 3) - ulWidth;

      /* Decrement the 8x8 row counter.                                     */
      ulCounter-= 0x0100;
      }
   while ( ulCounter && --ul8x8RowsToDisplay );

   /* Remember, in multiple aperture calls (SVGA systems and the like),     */
   /* we will not be asked to decode the entire image (ulRowsToDisplay).    */
   /* Therefore, we need to save where we where in the compressed data.     */
   *ppbCompressedData= pbData;
   *pulCounters= ulCounter;

   /* No error found (although we're not detecting them in this sample).    */
   return 0;
   }
