/* ** Command & Conquer Red Alert(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program 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 3 of the License, or ** (at your option) any later version. ** ** This program 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 this program. If not, see . */ /**************************************************************************** * * C O N F I D E N T I A L -- W E S T W O O D S T U D I O S * *---------------------------------------------------------------------------- * * PROJECT * VQAPlay32 library. (32-Bit protected mode) * * FILE * drawer.c * * DESCRIPTION * Frame drawing and page flip control. * * PROGRAMMER * Bill Randolph * Denzil E. Long, Jr. * * DATE * June 26, 1995 * *---------------------------------------------------------------------------- * * PUBLIC * VQA_Configure_Drawer - Configure the drawer routines. * * PRIVATE * Select_Frame - Selects frame to draw and preforms frame * skip. * Prepare_Frame - Process/Decompress frame information. * DrawFrame_Xmode - Draws a frame directly to Xmode screen. * DrawFrame_XmodeBuf - Draws a frame in Xmode format to a buffer. * DrawFrame_XmodeVRAM - Draws a frame in Xmode with resident * Codebook. * PageFlip_Xmode - Page flip Xmode display. * DrawFrame_MCGA - Draws a frame directly to MCGA screen. * PageFlip_MCGA - Page flip MCGA display. * DrawFrame_MCGABuf - Draws a frame in MCGA format to a buffer. * PageFlip_MCGABuf - Page flip a buffered MCGA display. * DrawFrame_VESA640 - Draws a frame in VESA640 format. * DrawFrame_VESA320_32K - Draws a frame to VESA320_32K screen. * DrawFrame_VESA320_32KBuf - Draws a frame in VESA320_32K format to a * buffer. * PageFlip_VESA - Page flip VESA display. * DrawFrame_Buffer - Draw a frame to a buffer. * PageFlip_Nop - Do nothing page flip. * UnVQ_Nop - Do nothing UnVQ. * Mask_Rect - Sets non-drawable rectangle in image. * Mask_Pointers - Mask vector pointer that are in the mask * rectangle. * ****************************************************************************/ #include #include #include #include #include #include #include "vq.h" #include "unvq.h" #include "vqaplayp.h" #include /*--------------------------------------------------------------------------- * PRIVATE DECLARATIONS *-------------------------------------------------------------------------*/ static long Select_Frame(VQAHandleP *vqap); static void Prepare_Frame(VQAData *vqabuf); #if(VQAMCGA_ON) static long DrawFrame_MCGABuf(VQAHandle *vqa); static long PageFlip_MCGABuf(VQAHandle *vqa); static long DrawFrame_MCGA(VQAHandle *vqa); static long PageFlip_MCGA(VQAHandle *vqa); #endif /* VQAMCGA_ON */ #if(VQAXMODE_ON) static long DrawFrame_XmodeBuf(VQAHandle *vqa); static long DrawFrame_Xmode(VQAHandle *vqa); static long DrawFrame_XmodeVRAM(VQAHandle *vqa); static void PageFlip_Xmode(VQAHandle *vqabuf); #endif /* VQAXMODE_ON */ #if(VQAVESA_ON) static long DrawFrame_VESA640(VQAHandle *vqa); static long DrawFrame_VESA320_32K(VQAHandle *vqa); static long DrawFrame_VESA320_32KBuf(VQAHandle *vqa); static void PageFlip_VESA(VQAHandle *vqabuf); #endif /* VQAVESA_ON */ static long DrawFrame_Buffer(VQAHandle *vqa); static long PageFlip_Nop(VQAHandle *vqa); #ifndef PHARLAP_TNT static void cdecl UnVQ_Nop(unsigned char *codebook, unsigned char *pointers, unsigned char *buffer, unsigned long blocksperrow, unsigned long numrows, unsigned long bufwidth); #else static void cdecl UnVQ_Nop(unsigned char *codebook, unsigned char *pointers, FARPTR buffer, unsigned long blocksperrow, unsigned long numrows, unsigned long bufwidth); #endif #if(0) static void Mask_Rect(VQAHandle *vqa, unsigned long x1, unsigned long y1, unsigned long x2, unsigned long y2); static void Mask_Pointers(VQAData *vqabuf); #endif /**************************************************************************** * * NAME * VQA_Configure_Drawer - Configure the drawer routines. * * SYNOPSIS * VQA_Configure_Drawer(VQA) * * void VQA_Configure_Drawer(VQAHandleP *); * * FUNCTION * Configure the drawing system for the current movie and configuration * options. * * INPUTS * VQA - Pointer to private VQAHandle. * * RESULT * NONE * ****************************************************************************/ void VQA_Configure_Drawer(VQAHandleP *vqap) { VQAData *vqabuf; VQAConfig *config; VQAHeader *header; VQADrawer *drawer; long origin; long blkdim; /* Dereference commonly used data members for quicker access. */ vqabuf = vqap->VQABuf; drawer = &vqabuf->Drawer; header = &vqap->Header; config = &vqap->Config; origin = (config->DrawFlags & VQACFGF_ORIGIN); /*------------------------------------------------------------------------- * SET THE DRAW POSITION OF THE MOVIE. * * X1 = -1 -- Center image of the X axis, otherwise use X1 value. * Y1 = -1 -- Center image of the Y axis, otherwise use Y1 value. *-----------------------------------------------------------------------*/ if ((config->X1 == -1) && (config->Y1 == -1)) { #if(VQAVIDEO_ON) drawer->X1 = ((drawer->Display->XRes - header->image_width) / 2); drawer->Y1 = ((drawer->Display->YRes - header->image_height) / 2); #else /* VQAVIDEO_ON */ drawer->X1 = ((drawer->ImageWidth - header->ImageWidth) / 2); drawer->Y1 = ((drawer->ImageHeight - header->ImageHeight) / 2); #endif /* VQAVIDEO_ON */ drawer->X2 = ((drawer->X1 + header->ImageWidth) - 1); drawer->Y2 = ((drawer->Y1 + header->ImageHeight) - 1); } else { switch (origin) { default: case VQACFGF_TOPLEFT: drawer->X1 = config->X1; drawer->Y1 = config->Y1; drawer->X2 = ((drawer->X1 + header->ImageWidth) - 1); drawer->Y2 = ((drawer->Y1 + header->ImageHeight) - 1); break; case VQACFGF_BOTLEFT: drawer->X1 = config->X1; drawer->Y1 = (drawer->ImageHeight - config->Y1); drawer->X2 = ((drawer->X1 + header->ImageWidth) - 1); drawer->Y2 = ((drawer->Y2 - header->ImageHeight) - 1); break; case VQACFGF_BOTRIGHT: drawer->X1 = (drawer->ImageWidth - config->X1); drawer->Y1 = (drawer->ImageHeight - config->Y1); drawer->X2 = (drawer->X1 - header->ImageWidth); drawer->Y2 = (drawer->Y1 - header->ImageHeight); break; } } /*------------------------------------------------------------------------- * INITIALIZE THE UNVQ ROUTINE FOR THE SPECIFIED VIDEO MODE AND BLOCK SIZE. *-----------------------------------------------------------------------*/ /* Pre-compute commonly used values for speed. */ drawer->BlocksPerRow = header->ImageWidth / header->BlockWidth; drawer->NumRows = header->ImageHeight / header->BlockHeight; drawer->NumBlocks = drawer->BlocksPerRow * drawer->NumRows; blkdim = BLOCK_DIM(header->BlockWidth, header->BlockHeight); /* Initialize draw routine vectors to a NOP routine in order to prevent * a crash. */ vqabuf->UnVQ = UnVQ_Nop; vqabuf->Page_Flip = PageFlip_Nop; /* If the client specifies buffering then go ahead an set the unvq * vector. All of the buffered modes use the same unvq routines. */ if (config->DrawFlags & VQACFGF_BUFFER) { switch (blkdim) { #if(VQABLOCK_2X2) case BLOCK_2X2: vqabuf->UnVQ = UnVQ_2x2; break; #endif #if(VQABLOCK_2X3) case BLOCK_2X3: vqabuf->UnVQ = UnVQ_2x3; break; #endif #if(VQABLOCK_4X2) case BLOCK_4X2: vqabuf->UnVQ = UnVQ_4x2; break; #endif #if(VQABLOCK_4X4) case BLOCK_4X4: vqabuf->UnVQ = UnVQ_4x4; break; #endif default: break; } } /* Initialize the draw vectors for the specified video mode. */ switch (config->Vmode) { /* MCGA */ #if(VQAMCGA_ON) case MCGA: if (config->DrawFlags & VQACFGF_BUFFER) { vqabuf->Draw_Frame = DrawFrame_MCGABuf; vqabuf->Page_Flip = PageFlip_MCGABuf; } else { vqabuf->Draw_Frame = DrawFrame_MCGA; vqabuf->Page_Flip = PageFlip_MCGA; /* MCGA uses the same unvq routines that are used for unvqing * to a buffer because MCGA mode is just another buffer. However, * instead of drawing to an allocated RAM buffer we are drawing * directly to the VRAM video buffer. */ switch (blkdim) { #if(VQABLOCK_2X2) case BLOCK_2X2: vqabuf->UnVQ = UnVQ_2x2; break; #endif #if(VQABLOCK_2X3) case BLOCK_2X3: vqabuf->UnVQ = UnVQ_2x3; break; #endif #if(VQABLOCK_4X2) case BLOCK_4X2: #if(!VQAWOOFER_ON) vqabuf->UnVQ = UnVQ_4x2; #else if (config->DrawFlags & VQACFGF_WOOFER) { vqabuf->UnVQ = UnVQ_4x2_Woofer; } else { vqabuf->UnVQ = UnVQ_4x2; } #endif break; #endif #if(VQABLOCK_4X4) case BLOCK_4X4: vqabuf->UnVQ = UnVQ_4x4; break; #endif } } /* Pre-compute the draw offset for speed. */ drawer->ScreenOffset = ((320 * drawer->Y1) + drawer->X1); break; #endif /* VQAMCGA_ON */ /* XMODE */ #if(VQAXMODE_ON) case XMODE_320X200: case XMODE_320X240: if (config->DrawFlags & VQACFGF_BUFFER) { vqabuf->Draw_Frame = DrawFrame_XmodeBuf; vqabuf->Page_Flip = PageFlip_Xmode; } else { vqabuf->Page_Flip = PageFlip_Xmode; if (config->DrawFlags & VQACFGF_VRAMCB) { vqabuf->Draw_Frame = DrawFrame_XmodeVRAM; switch (blkdim) { #if(VQABLOCK_4X2) case BLOCK_4X2: vqabuf->UnVQ = UnVQ_4x2_XmodeCB; break; #endif /* VQABLOCK_4X2 */ } } else { vqabuf->Draw_Frame = DrawFrame_Xmode; switch (blkdim) { #if(VQABLOCK_4X2) case BLOCK_4X2: vqabuf->UnVQ = UnVQ_4x2_Xmode; break; #endif /* VQABLOCK_4X2 */ } } } /* Pre-compute the draw offset for speed. */ drawer->ScreenOffset = (((320 / 4) * drawer->Y1) + (drawer->X1 / 4)); break; #endif /* VQAXMODE_ON */ /* VESA */ #if(VQAVESA_ON) /* Currently this is a buffered mode, but should be optimized for * for screen direct. */ case VESA_640X480_256: vqabuf->Draw_Frame = DrawFrame_VESA640; vqabuf->Page_Flip = PageFlip_VESA; break; case VESA_320X200_32K_1: if (config->DrawFlags & VQACFGF_BUFFER) { vqabuf->Draw_Frame = DrawFrame_VESA320_32KBuf; } else { vqabuf->Draw_Frame = DrawFrame_VESA320_32K; switch (blkdim) { #if(VQABLOCK_4X2) case BLOCK_4X2: vqabuf->UnVQ = UnVQ_4x2_VESA320_32K; break; #endif } } break; #endif /* VQAVESA_ON */ /* Purely buffered (Video refresh is up to the client. */ default: vqabuf->Draw_Frame = DrawFrame_Buffer; /* Pre-compute the draw offset for speed. */ drawer->ScreenOffset = ((drawer->ImageWidth * drawer->Y1)+drawer->X1); break; } } /**************************************************************************** * * NAME * Select_Frame - Selects frame to draw and preforms frame skip. * * SYNOPSIS * Error = Select_Frame(VQA) * * long Select_Frame(VQAHandleP *); * * FUNCTION * Select a frame to draw. This is were the frame skipping/delay is * performed. * * INPUTS * VQA - Pointer to private VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long Select_Frame(VQAHandleP *vqap) { VQAData *vqabuf; VQADrawer *drawer; VQAConfig *config; VQAFrameNode *curframe; long curtime; long desiredframe; /* Dereference commonly used data members for quicker access. */ config = &vqap->Config; vqabuf = vqap->VQABuf; drawer = &vqabuf->Drawer; curframe = drawer->CurFrame; /* Make sure the current frame is drawable. If the frame is not ready * then we must wait for the loader to catch up. */ if ((curframe->Flags & VQAFRMF_LOADED) == 0) { drawer->WaitsOnLoader++; return (VQAERR_NOBUFFER); } /* If single stepping then return with the next frame.*/ if (config->OptionFlags & VQAOPTF_STEP) { drawer->LastFrame = curframe->FrameNum; return (0); } /* Find the frame # we should play (rounded to nearest frame): */ curtime = VQA_GetTime(vqap); desiredframe = ((curtime * config->FrameRate) / VQA_TIMETICKS); #if(VQAMONO_ON) drawer->DesiredFrame = desiredframe; #endif /* Handle the cases where the player is going so fast that it's not time * to draw this frame yet. * * - If the Drawer is using a slower frame rate than the Loader, use a * delta-time-based wait; otherwise, use the frame number as the wait. */ if (config->DrawRate != config->FrameRate) { if (curtime - drawer->LastTime < (VQA_TIMETICKS / config->DrawRate)) { return (VQAERR_NOT_TIME); } } else { if (curframe->FrameNum > desiredframe) { return (VQAERR_NOT_TIME); } } /* Make sure we draw at least 5 frames per second */ if ((curframe->FrameNum - drawer->LastFrame) >= (config->FrameRate / 5)) { drawer->LastFrame = curframe->FrameNum; return (0); } /* If frame skipping is disabled then draw every frame. */ if (config->DrawFlags & VQACFGF_NOSKIP) { drawer->LastFrame = curframe->FrameNum; return (0); } /* Handle the case where the player is going too slow, so we have to skip * some frames: * * - If this is a Key Frame, draw it * - If this frame's # is less than what we're supposed to draw, skip it * (Because the 1st 'desiredframe' will be 0, FrameNum MUST be typecast * to signed WORD for the comparison; otherwise, the comparison uses * UWORDs, and the first frame is always skipped.) * - If this is a palette-set frame, set the palette before skipping it * - Loop until we get the frame we need, or there's no frames available */ while (1) { /* No frame available; return */ if ((curframe->Flags & VQAFRMF_LOADED) == 0) { return (VQAERR_NOBUFFER); } /* Force drawing of a Key Frame */ if (curframe->Flags & VQAFRMF_KEY) { break; } /* Skip the frame */ if (curframe->FrameNum < desiredframe) { /* Handle a palette in a skipped frame: * * - Stash the palette in Drawer.Palette_24 * - Set the Drawer.Flags VQADRWF_SETPAL bit, to tell the page-flip * routines that this palette must be set */ if (curframe->Flags & VQAFRMF_PALETTE) { /* Un-LCW if needed */ if (curframe->Flags & VQAFRMF_PALCOMP) { curframe->PaletteSize = LCW_Uncompress((char *)curframe->Palette + curframe->PalOffset, (char *)curframe->Palette, vqabuf->Max_Pal_Size); curframe->Flags &= ~VQAFRMF_PALCOMP; } /* Stash the palette */ memcpy(drawer->Palette_24, curframe->Palette, curframe->PaletteSize); drawer->CurPalSize = curframe->PaletteSize; drawer->Flags |= VQADRWF_SETPAL; } /* Invoke callback with NULL screen ptr */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(NULL, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } /* Skip the frame */ curframe->Flags = 0L; curframe = curframe->Next; drawer->CurFrame = curframe; drawer->NumSkipped++; } else { break; } } drawer->LastFrame = curframe->FrameNum; drawer->LastTime = curtime; return (0); } /**************************************************************************** * * NAME * Prepare_Frame - Process/Decompress frame information. * * SYNOPSIS * Prepare_Frame(VQAData) * * void Prepare_Frame(VQAData *); * * FUNCTION * Decompress and preprocess the various frame elements (codebook, * pointers, palette, etc...) * * INPUTS * VQAData - Pointer to VQAData structure. * * RESULT * NONE * ****************************************************************************/ static void Prepare_Frame(VQAData *vqabuf) { VQADrawer *drawer; VQAFrameNode *curframe; VQACBNode *codebook; /* Dereference commonly used data members for quicker access. */ drawer = &vqabuf->Drawer; curframe = drawer->CurFrame; codebook = curframe->Codebook; /* Decompress the codebook, if needed */ if (codebook->Flags & VQACBF_CBCOMP) { /* Decompress the codebook. */ LCW_Uncompress((char *)codebook->Buffer + codebook->CBOffset, (char *)codebook->Buffer, vqabuf->Max_CB_Size); /* Mark as uncompressed for the next time we use it */ codebook->Flags &= (~VQACBF_CBCOMP); } /* Decompress the palette, if needed */ if (curframe->Flags & VQAFRMF_PALCOMP) { curframe->PaletteSize = LCW_Uncompress((char *)curframe->Palette + curframe->PalOffset,(char *)curframe->Palette,vqabuf->Max_Pal_Size); /* Mark as uncompressed */ curframe->Flags &= ~VQAFRMF_PALCOMP; } /* Decompress the pointer data, if needed */ if (curframe->Flags & VQAFRMF_PTRCOMP) { LCW_Uncompress((char *)curframe->Pointers + curframe->PtrOffset, (char *)curframe->Pointers, vqabuf->Max_Ptr_Size); /* Mark as uncompressed */ curframe->Flags &= ~VQAFRMF_PTRCOMP; } /* Mask the pointers */ #if(0) Mask_Pointers(vqabuf); #endif } #if(VQAXMODE_ON) /**************************************************************************** * * NAME * DrawFrame_Xmode - Draws a frame in Xmode format (Screen direct). * * SYNOPSIS * Error = DrawFrame_Xmode(VQA) * * long DrawFrame_Xmode(VQAHandle *); * * FUNCTION * Algorithm: * - Skip frames * - UnLCW frame * - Un-VQ into video RAM * - Wait on Update_Enabled * - Set the Flipper's CurFrame * - Set Update_Enabled * - Go to next frame * - User_Update: * Flip X-Page * Set Palette from Flipper.CurFrame * * This function implements a sort of cooperative multitasking. If the * Drawer hits a "wait state", where it has to wait for Update_Enabled * to toggle, it sets a flag and returns. This flag is checked on entry * to see if we need to jump to the proper execution point. This should * improve performance on some platforms. * * This routine handles small images by UnVQ'ing into the correct spot on * the Xmode screen. * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_Xmode(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; unsigned char *scrn; long rc; /* Dereference data members for quick access */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; config = &((VQAHandleP *)vqa)->Config; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); /* Dereference current frame for quicker access */ curframe = drawer->CurFrame; /* Un-VQ the image */ scrn = GetXHidPage(); vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, scrn + drawer->ScreenOffset, drawer->BlocksPerRow, drawer->NumRows, 320); /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(scrn, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Dereference current frame for quicker access */ curframe = drawer->CurFrame; /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * DrawFrame_XmodeBuf - Draws a frame in Xmode format to a buffer. * * SYNOPSIS * Error = DrawFrame_XmodeBuf(VQA) * * long DrawFrame_XmodeBuf(VQAHandle *); * * FUNCTION * Algorithm: * - Skip frames * - UnLCW frame * - Un-VQ into ImageBuf * - Copy ImageBuf to video RAM * - Wait on Update_Enabled * - Set the Flipper's CurFrame * - Set Update_Enabled * - Go to next frame * - User_Update: * Flip X-Page * Set Palette from Flipper.CurFrame * * This function implements a sort of cooperative multitasking. If the * Drawer hits a "wait state", where it has to wait for Update_Enabled * to toggle, it sets a flag and returns. This flag is checked on entry * to see if we need to jump to the proper execution point. This should * improve performance on some platforms. * * This routine handles small images by UnVQ'ing into the upper-left * corner of ImageBuf, then copying ImageBuf into the correct part of the * Xmode screen. * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_XmodeBuf(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAHeader *header; VQAConfig *config; unsigned char *scrn; long rc; /* Dereference data members for quicker access */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; header = &((VQAHandleP *)vqa)->Header; config = &((VQAHandleP *)vqa)->Config; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; /* Un-VQ the image */ vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, drawer->ImageBuf, drawer->BlocksPerRow, drawer->NumRows, header->ImageWidth); /* Copy the buffer */ scrn = GetXHidPage(); if ((header->ImageWidth < 320) || (header->ImageHeight < 200)) { Xmode_Blit(drawer->ImageBuf, scrn + drawer->ScreenOffset, header->ImageWidth, header->ImageHeight); } else { Xmode_BufferCopy_320x200(drawer->ImageBuf,scrn + drawer->ScreenOffset); } /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(scrn, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * DrawFrame_XmodeVRAM - Draws a frame in Xmode with resident Codebook. * * SYNOPSIS * Error = DrawFrame_XmodeVRAM(VQA) * * long DrawFrame_XmodeVRAM(VQAHandle *); * * FUNCTION * Algorithm: * - Download Codebook if it isn't already (do this before skipping * frames, so Select_Frame will smooth out the delay) * - Skip frames * - UnLCW frame * - Convert Pointers to VRAM format * - Un-VQ by copying codebook blocks within VRAM * - Wait on Update_Enabled * - Set the Flipper's CurFrame * - Set Update_Enabled * - Go to next frame * - User_Update: * Flip X-Page * Set Palette from Flipper.CurFrame * * This function implements a sort of cooperative multitasking. If the * Drawer hits a "wait state", where it has to wait for Update_Enabled * to toggle, it sets a flag and returns. This flag is checked on entry * to see if we need to jump to the proper execution point. This should * improve performance on some platforms. * * This routine handles small images by UnVQ'ing into the correct spot on * the Xmode screen. * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_XmodeVRAM(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; unsigned char *scrn; long rc; /* Dereference data members for quicker access */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; config = &((VQAHandleP *)vqa)->Config; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; /* Download codebook to VRAM */ if ((curframe->Codebook->Flags & VQACBF_DOWNLOADED) == 0) { Upload_4x2CB(curframe->Codebook->Buffer, ((VQAHandleP *)vqa)->Header.CBentries + ((VQAHandleP *)vqa)->Header.Num1Colors); curframe->Codebook->Flags |= VQACBF_DOWNLOADED; } /* Convert pointers to VRAM format */ XlatePointers(curframe->Pointers, drawer->NumBlocks); /* Un-VQ the image */ scrn = GetXHidPage(); vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, scrn + drawer->ScreenOffset, drawer->BlocksPerRow, drawer->NumRows, 320); /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(scrn, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * PageFlip_Xmode - Page flip Xmode display. * * SYNOPSIS * PageFlip_Xmode(VQA) * * void PageFlip_Xmode(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * NONE * ****************************************************************************/ static void PageFlip_Xmode(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; unsigned char *pal; VQAConfig *config; long palsize; long slowpal; /* Dereference commonly used data members for quicker access. */ config = &((VQAHandleP *)vqa)->Config; vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; curframe = vqabuf->Flipper.CurFrame; /* Pre-decode 'vqa' for speed */ pal = curframe->Palette; palsize = curframe->PaletteSize; slowpal = (config->OptionFlags & VQAOPTF_SLOWPAL) ? 1 : 0; /* - If this is a palette-set frame: * - Wait for NoVB (active scan) * - Flip the page (doesn't take effect until next active scan * - Wait for VB * - Set the palette * - Otherwise, just flip the page */ if (curframe->Flags & VQAFRMF_PALETTE) { WaitNoVB(vqabuf->VBIBit); FlipXPage(); WaitVB(vqabuf->VBIBit); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(pal, palsize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)pal, (long)palsize); } } else if (drawer->Flags & VQADRWF_SETPAL) { drawer->Flags &= (~VQADRWF_SETPAL); WaitNoVB(vqabuf->VBIBit); FlipXPage(); WaitVB(vqabuf->VBIBit); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(drawer->Palette_24, drawer->CurPalSize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)drawer->Palette_24, (long)drawer->CurPalSize); } } else { FlipXPage(); } } #endif /* VQAXMODE_ON */ #if(VQAMCGA_ON) /**************************************************************************** * * NAME * DrawFrame_MCGA - Draws a frame directly to MCGA screen. * * SYNOPSIS * Error = DrawFrame_MCGA(VQA) * * long DrawFrame_MCGA(VQAHandle *); * * FUNCTION * Algorithm: * - Skip frames * - UnLCW frame * - Wait on Update_Enabled * - Set Update_Enabled * - Go to next frame * - User_Update: * set palette * UnVQ to screen * * This function implements a sort of cooperative multitasking. If the * Drawer hits a "wait state", where it has to wait for Update_Enabled * to toggle, it sets a flag and returns. This flag is checked on entry * to see if we need to jump to the proper execution point. This should * improve performance on some platforms. * * This routine handles small images by UnVQ'ing into the correct spot on * the screen. * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_MCGA(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; long rc; /* Dereference commonly used data members for quicker access */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Select the frame to draw. */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * PageFlip_MCGA - Page flip MCGA display. * * SYNOPSIS * PageFlip_MCGA(VQA) * * long PageFlip_MCGA(VQAHandle *); * * FUNCTION * Since the MCGA mode only has one buffer, the drawing is actually done * at this point. * * INPUTS * VQA - Pointer to VQAHandle structure. * * RESULT * Error - 0 if successfull, otherwise VQAERR_??? * ****************************************************************************/ static long PageFlip_MCGA(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; unsigned char *pal; unsigned char *ptrs; unsigned char *cb; long palsize; long slowpal; long blocksperrow; long numrows; #ifndef PHARLAP_TNT unsigned char *scrn; #else FARPTR scrn; #endif /* Dereference commonly used data members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; config = &((VQAHandleP *)vqa)->Config; drawer = &vqabuf->Drawer; curframe = vqabuf->Flipper.CurFrame; /*------------------------------------------------------------------------- * WAIT FOR THE VERTICAL BLANK TO SET THE PALETTE. *-----------------------------------------------------------------------*/ if ((curframe->Flags & VQAFRMF_PALETTE) || (drawer->Flags & VQADRWF_SETPAL)) { pal = curframe->Palette; palsize = curframe->PaletteSize; slowpal = (config->OptionFlags & VQAOPTF_SLOWPAL) ? 1 : 0; /* Wait for the VBlank. */ WaitNoVB(vqabuf->VBIBit); WaitVB(vqabuf->VBIBit); /* Set the palette. */ if (curframe->Flags & VQAFRMF_PALETTE) { if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(pal, palsize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)pal, (long)palsize); } } else if (drawer->Flags & VQADRWF_SETPAL) { drawer->Flags &= (~VQADRWF_SETPAL); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(drawer->Palette_24, drawer->CurPalSize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)drawer->Palette_24, (long)drawer->CurPalSize); } } } /*------------------------------------------------------------------------- * UNVQ THE FRAME DIRECTLY TO THE MCGA SCREEN. *-----------------------------------------------------------------------*/ /* Get screen address, blocks per row and number of rows. */ #ifndef PHARLAP_TNT scrn = (unsigned char *)(0xA0000 + (unsigned long)drawer->ScreenOffset); #else FP_SET(scrn, drawer->ScreenOffset, 0x1C); #endif blocksperrow = drawer->BlocksPerRow; numrows = drawer->NumRows; ptrs = curframe->Pointers; cb = curframe->Codebook->Buffer; vqabuf->UnVQ(cb, ptrs, scrn, blocksperrow, numrows, 320); /* Process captions. */ if ((((VQAHandleP *)vqa)->Caption != NULL) && (config->OptionFlags & VQAOPTF_CAPTIONS)) { DoCaptions(((VQAHandleP *)vqa)->Caption, curframe->FrameNum); } if ((((VQAHandleP *)vqa)->EVA != NULL) && (config->OptionFlags & VQAOPTF_EVA)) { DoCaptions(((VQAHandleP *)vqa)->EVA, curframe->FrameNum); } /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(NULL, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } return (0); } /**************************************************************************** * * NAME * DrawFrame_MCGABuf - Draws a frame in MCGA format to a buffer. * * SYNOPSIS * Error = DrawFrame_MCGABuf(VQA) * * long DrawFrame_MCGABuf(VQAHandle *); * * FUNCTION * Algorithm: * - Skip frames * - UnLCW frame * - Wait on Update_Enabled (can't use imgbuf til User_Update's done) * - Un-VQ into ImageBuf * - Set the Flipper's CurFrame * - Set Update_Enabled * - Go to next frame * - User_Update: * set Palette from Flipper.CurFrame * copy ImageBuf to screen * * This function implements a sort of cooperative multitasking. If the * Drawer hits a "wait state", where it has to wait for Update_Enabled * to toggle, it sets a flag and returns. This flag is checked on entry * to see if we need to jump to the proper execution point. This should * improve performance on some platforms. * * This routine handles small images by UnVQ'ing into the upper-left * corner of ImageBuf, then copying ImageBuf onto the screen. * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_MCGABuf(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; long rc; #ifndef PHARLAP_TNT unsigned char *scrn; #else FARPTR scrn; #endif /* Dereference commonly used data members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; #ifndef PHARLAP_TNT scrn = drawer->ImageBuf; #else FP_SET(scrn, drawer->ImageBuf, 0x14); #endif /* Un-VQ the image */ vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, scrn, drawer->BlocksPerRow, drawer->NumRows, ((VQAHandleP *)vqa)->Header.ImageWidth); /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * PageFlip_MCGABuf - Page flip a buffered MCGA display. * * SYNOPSIS * PageFlip_MCGABuf(VQA) * * void PageFlip_MCGABuf(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successfull, otherwise VQAERR_??? * ****************************************************************************/ static long PageFlip_MCGABuf(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; unsigned char *pal; unsigned char *buf; unsigned char *scrn; long palsize; long slowpal; long imgwidth; long imgheight; /* Derefernce commonly used data members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; config = &((VQAHandleP *)vqa)->Config; drawer = &vqabuf->Drawer; curframe = vqabuf->Flipper.CurFrame; /* Pre-decode 'vqa' for speed */ pal = curframe->Palette; palsize = curframe->PaletteSize; slowpal = (config->OptionFlags & VQAOPTF_SLOWPAL) ? 1 : 0; /* - If this is a palette-set frame: * - Wait for the vertical blank * - Set the palette * - Copy ImageBuf to SEENPAGE: * - use blit routine if image is smaller than full-screen, since the * buffer copy assumes a full-screen image */ if (curframe->Flags & VQAFRMF_PALETTE) { WaitNoVB(vqabuf->VBIBit); WaitVB(vqabuf->VBIBit); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(pal, palsize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)pal, (long)palsize); } } else if (drawer->Flags & VQADRWF_SETPAL) { drawer->Flags &= (~VQADRWF_SETPAL); WaitNoVB(vqabuf->VBIBit); WaitVB(vqabuf->VBIBit); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(drawer->Palette_24, drawer->CurPalSize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)drawer->Palette_24, (long)drawer->CurPalSize); } } /* Draw image to the screen. */ imgwidth = ((VQAHandleP *)vqa)->Header.ImageWidth; imgheight = ((VQAHandleP *)vqa)->Header.ImageHeight; buf = drawer->ImageBuf; #ifndef PHARLAP_TNT scrn = (unsigned char *)0xA0000; #endif if ((imgwidth < 320) || (imgheight < 200)) { #ifndef PHARLAP_TNT scrn += drawer->ScreenOffset; #else scrn = (unsigned char *)drawer->ScreenOffset; #endif MCGA_Blit(buf, scrn, imgwidth, imgheight); } else { MCGA_BufferCopy(buf, NULL); } /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(NULL, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } return (0); } #endif /* VQAMCGA_ON */ #if(VQAVESA_ON) /**************************************************************************** * * NAME * DrawFrame_VESA640 - Draws a frame in VESA 640 format. * * SYNOPSIS * Error = DrawFrame_VESA640(VQA) * * long DrawFrame_VESA640(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_VESA640(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; long rc; #ifndef PHARLAP_TNT unsigned char *scrn; #else FARPTR scrn; #endif /* Dereference data members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); } /* Dereference current frame. */ curframe = drawer->CurFrame; /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { vqabuf->Drawer.WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } #ifndef PHARLAP_TNT scrn = drawer->ImageBuf + drawer->ScreenOffset; #else FP_SET(scrn, drawer->ImageBuf + drawer->ScreenOffset, 0x14); #endif /* Un-VQ the image */ vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, scrn, drawer->BlocksPerRow, drawer->NumRows, drawer->ImageWidth); /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * DrawFrame_VESA320_32K - Draws a frame in VESA 320 format. * * SYNOPSIS * Error = DrawFrame_VESA320_32K(VQA) * * long DrawFrame_VESA320_32K(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_VESA320_32K(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; long rc; long grain; /* Dereference data members for quicker access. */ config = &((VQAHandleP *)vqa)->Config; vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); /* Dereference current frame. */ curframe = drawer->CurFrame; /* Translate palette to 15-bit */ if (curframe->Flags & VQAFRMF_PALETTE) { TranslatePalette(curframe->Palette, drawer->Palette_15, curframe->PaletteSize); } else if (drawer->Flags & VQADRWF_SETPAL) { TranslatePalette(drawer->Palette_24, drawer->Palette_15, drawer->CurPalSize); } /* UnVQ directly to screen */ grain = ((VESAModeInfo *)(drawer->Display->Extended))->WinSize / ((VESAModeInfo *)(drawer->Display->Extended))->WinGranularity; #ifndef PHARLAP_TNT vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, drawer->Palette_15, grain, 0, 0); #else { FARPTR temp; FP_SET(temp, drawer->Palette_15, 0x14); vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, temp, grain, 0, 0); } #endif /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(0, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } } /* Wait for VQ_Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * DrawFrame_VESA320_32KBuf - Draws a frame in VESA320_32K format to a * buffer. * * SYNOPSIS * Error = DrawFrame_VESA320_32KBuf(VQA) * * long DrawFrame_VESA320_32KBuf(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * Error - 0 if successful, or VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_VESA320_32KBuf(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; long rc; long grain; /* Dereference data members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; config = &((VQAHandleP *)vqa)->Config; drawer = &vqabuf->Drawer; curframe = drawer->CurFrame; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); /* UnVQ buffered mode */ #ifndef PHARLAP_TNT vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, drawer->ImageBuf, drawer->BlocksPerRow, drawer->NumRows, ((VQAHandleP *)vqa)->Header.image_width); #else { FARPTR scrn; FP_SET(scrn, drawer->ImageBuf, 0x14); vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, scrn, drawer->BlocksPerRow, drawer->NumRows, ((VQAHandleP *)vqa)->Header.image_width); } #endif /* Translate the palette to 15-bit */ if (curframe->Flags & VQAFRMF_PALETTE) { TranslatePalette(curframe->Palette, drawer->Palette_15, curframe->PaletteSize); } else if (drawer->Flags & VQADRWF_SETPAL) { TranslatePalette(drawer->Palette_24, drawer->Palette_15, drawer->CurPalSize); } /* Copy the buffer */ grain = ((VESAModeInfo *)(drawer->Display->Extended))->WinSize / ((VESAModeInfo *)(drawer->Display->Extended))->WinGranularity; Buf_320x200_To_VESA_32K(drawer->ImageBuf, drawer->Palette_15, grain); /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(0, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { vqabuf->Flags &= (~VQADATF_DSLEEP); drawer->WaitsOnFlipper++; } /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * PageFlip_VESA - Page flip VESA display. * * SYNOPSIS * PageFlip_VESA(VQA) * * void PageFlip_VESA(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQAHandle. * * RESULT * NONE * ****************************************************************************/ static void PageFlip_VESA(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; unsigned char *pal; long palsize; long slowpal; long grain; /* Dereference date members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; config = &((VQAHandleP *)vqa)->Config; drawer = &vqabuf->Drawer; curframe = vqabuf->Flipper.CurFrame; /* Pre-decode 'vqa' for speed */ pal = curframe->Palette; palsize = curframe->PaletteSize; slowpal = (config->OptionFlags & VQAOPTF_SLOWPAL) ? 1 : 0; /* Set the palette */ if (curframe->Flags & VQAFRMF_PALETTE) { WaitNoVB(vqabuf->VBIBit); WaitVB(vqabuf->VBIBit); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(pal, palsize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)pal, (long)palsize); } } else if (drawer->Flags & VQADRWF_SETPAL) { drawer->Flags &= (~VQADRWF_SETPAL); WaitNoVB(vqabuf->VBIBit); WaitVB(vqabuf->VBIBit); if (!(config->OptionFlags & VQAOPTF_PALOFF)) { SetPalette(drawer->Palette_24, drawer->CurPalSize, slowpal); } /* Notify the client of the palette change. */ if ((config->NotifyFlags & VQAEVENT_PALETTE) && (config->EventHandler != NULL)) { config->EventHandler(VQAEVENT_PALETTE, (void *)drawer->Palette_24, (long)drawer->CurPalSize); } } /* Copy the buffer */ grain = ((VESAModeInfo *)(drawer->Display->Extended))->WinSize / ((VESAModeInfo *)(drawer->Display->Extended))->WinGranularity; switch (((VQAHandleP *)vqa)->Header.image_width) { case 320: if (config->DrawFlags & VQACFGF_SCALEX2) { Buf_320x200_To_VESA_640x400(drawer->ImageBuf, grain); } else { Buf_320x200_To_VESA_320x200(drawer->ImageBuf, grain); } break; default: VESA_Blit_640x480(drawer->Display, drawer->ImageBuf, drawer->X1, drawer->Y1, ((VQAHandleP *)vqa)->Header.image_width, ((VQAHandleP *)vqa)->Header.image_height); break; } /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(drawer->ImageBuf, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } } #endif /* VQAVESA_ON */ /**************************************************************************** * * NAME * DrawFrame_Buffer - Draw a frame to a buffer. * * SYNOPSIS * Error = DrawFrame_Buffer(VQA) * * long DrawFrame_Buffere(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQA handle. * * RESULT * Error - 0 if successful, otherwise VQAERR_??? error code. * ****************************************************************************/ static long DrawFrame_Buffer(VQAHandle *vqa) { VQAData *vqabuf; VQADrawer *drawer; VQAFrameNode *curframe; VQAConfig *config; long rc; #ifndef PHARLAP_TNT unsigned char *buff; #else FARPTR buff; #endif /* Dereference data members for quicker access. */ config = &((VQAHandleP *)vqa)->Config; vqabuf = ((VQAHandleP *)vqa)->VQABuf; drawer = &vqabuf->Drawer; /* Check our "sleep" state */ if (!(vqabuf->Flags & VQADATF_DSLEEP)) { /* Find the frame to draw */ if ((rc = Select_Frame((VQAHandleP *)vqa)) != 0) { return (rc); } /* Uncompress the frame data */ Prepare_Frame(vqabuf); } /* Wait for Update_Enabled to be set low */ if (vqabuf->Flags & VQADATF_UPDATE) { vqabuf->Flags |= VQADATF_DSLEEP; return (VQAERR_SLEEPING); } if (vqabuf->Flags & VQADATF_DSLEEP) { drawer->WaitsOnFlipper++; vqabuf->Flags &= (~VQADATF_DSLEEP); } /* Dereference current frame for quicker access. */ curframe = drawer->CurFrame; #ifndef PHARLAP_TNT buff = (unsigned char *)(drawer->ImageBuf + drawer->ScreenOffset); #else FP_SET(buff, drawer->ImageBuf + drawer->ScreenOffset, 0x14); #endif /* Un-VQ the image */ vqabuf->UnVQ(curframe->Codebook->Buffer, curframe->Pointers, buff, drawer->BlocksPerRow, drawer->NumRows, drawer->ImageWidth); /* Update data for mono output */ drawer->LastFrameNum = curframe->FrameNum; /* Tell the flipper which frame to use */ vqabuf->Flipper.CurFrame = curframe; /* Set the page-avail flag for the flipper */ vqabuf->Flags |= VQADATF_UPDATE; /* Invoke user's callback routine */ if (config->DrawerCallback != NULL) { if ((config->DrawerCallback(drawer->ImageBuf, curframe->FrameNum)) != 0) { return (VQAERR_EOF); } } /* Move to the next frame */ drawer->CurFrame = curframe->Next; return (0); } /**************************************************************************** * * NAME * UnVQ_Nop - Do nothing UnVQ. * * SYNOPSIS * UnVQ_Nop(Codebook, Pointers, Buffer, BPR, Rows, BufWidth) * * void UnVQ_Nop(unsigned char *, unsigned char *, unsigned char *, * unsigned long, unsigned long, unsigned long); * FUNCTION * * INPUTS * Codebook - Not used. (Prototype placeholder) * Pointers - Not used. (Prototype placeholder) * Buffer - Not used. (Prototype placeholder) * BPR - Not used. (Prototype placeholder) * Rows - Not used. (Prototype placeholder) * BufWidth - Not used. (Prototype placeholder) * * RESULT * NONE * ****************************************************************************/ #ifndef PHARLAP_TNT static void cdecl UnVQ_Nop(unsigned char *codebook, unsigned char *pointers, unsigned char *buffer, unsigned long blocksperrow, unsigned long numrows, unsigned long bufwidth) #else static void cdecl UnVQ_Nop(unsigned char *codebook, unsigned char *pointers, FARPTR buffer, unsigned long blocksperrow, unsigned long numrows, unsigned long bufwidth) #endif { /* Suppress compiler warnings */ codebook = codebook; pointers = pointers; buffer = buffer; blocksperrow = blocksperrow; numrows = numrows; bufwidth = bufwidth; } /**************************************************************************** * * NAME * PageFlip_Nop - Do nothing page flip. * * SYNOPSIS * PageFlip_Nop(VQA) * * void PageFlip_Nop(VQAHandle *); * * FUNCTION * * INPUTS * VQA - Pointer to VQA handle. * * RESULT * NONE * ****************************************************************************/ static long PageFlip_Nop(VQAHandle *vqa) { vqa = vqa; return (0); } #if(0) /**************************************************************************** * * NAME * Mask_Rect - Sets non-drawable rectangle in image. * * SYNOPSIS * Mask_Rect(VQA, X1, Y1, X2, Y2) * * void Mask_Rect(VQAHandle *, unsigned long, unsigned long, * unsigned long, unsigned long); * * FUNCTION * * INPUTS * VQA - Pointer to VQA handle. * X1 - X coordinate of upper-left corner * Y1 - Y coordinate of upper-left corner * X2 - X coordinate of lower-right corner * Y2 - Y coordinate of lower-right corner * * RESULT * NONE * ****************************************************************************/ static void Mask_Rect(VQAHandle *vqa, unsigned long x1, unsigned long y1, unsigned long x2, unsigned long y2) { VQAData *vqabuf; VQADrawer *drawer; VQAHeader *header; long blocks_per_row; /* Dereference data members for quicker access. */ vqabuf = ((VQAHandleP *)vqa)->VQABuf; header = &((VQAHandleP *)vqa)->Header; drawer = &vqabuf->Drawer; /* Clip coords to image size */ if (x1 < vqabuf->Drawer.X1) { x1 = vqabuf->Drawer.X1; } if (y1 < vqabuf->Drawer.Y1) { y1 = vqabuf->Drawer.Y1; } if (x2 > vqabuf->Drawer.X2) { x2 = vqabuf->Drawer.X2; } if (y2 > vqabuf->Drawer.Y2) { y2 = vqabuf->Drawer.Y2; } /* Convert pixel coords to block coords */ x1 /= header->block_width; x2 /= header->block_width; y1 /= header->block_height; y2 /= header->block_height; /* Compute the mask values */ blocks_per_row = (header->image_width / header->block_width); vqabuf->Drawer.MaskStart = blocks_per_row * y1 + x1; if (x1 == x2) { drawer->MaskWidth = 0; } else { drawer->MaskWidth = x2 - x1 + 1; } if (y1 == y2) { drawer->MaskHeight = 0; } else { drawer->MaskHeight = y2 - y1 + 1; } } /**************************************************************************** * * NAME * Mask_Pointers - Mask vector pointer that are in the mask rectangle. * * SYNOPSIS * Mask_Pointers(VQAData) * * void Mask_Pointers(VQAData *); * * FUNCTION * * INPUTS * VQAData - Pointer to VQAData structure. * * RESULT * NONE * ****************************************************************************/ static void Mask_Pointers(VQAData *vqabuf) { VQADrawer *drawer; VQAFrameNode *curframe; unsigned long *ptr; unsigned long i,j; unsigned long start; /* Dereference data members for quicker access. */ drawer = &vqabuf->Drawer; curframe = drawer->CurFrame; start = vqabuf->Drawer.MaskStart; for (i = 0; i < drawer->MaskHeight; i++) { ptr = (unsigned long *)(curframe->Pointers) + start; for (j = 0; j < drawer->MaskWidth; j++) { ptr[j] = VQA_MASK_POINTER; } start += drawer->BlocksPerRow; } } #endif