// File : fwCostum.h // Author : John Wojcik ( QuietBloke ) // Created : June 2000 // Desc : 2D Game Framework Costume manager. This manager // allows textures to easily be loaded into video // memory and then applied to a Sprite. This manager // allows multiple image textures to be loaded with a // single call. Textures can be 4,8 or 16 bit TIM's. // // History : // Date Author Description // -------- --------------- ---------------------------------------- #include #include // #include "fwcostum.h" #include "fw.h" typedef struct { unsigned short tPage; // What page the image can be found unsigned short pmode; // bit depth of image unsigned short height; // height of image in pixels unsigned short width; // width of image in pixels unsigned short xOffset; // left offset of image in page unsigned short yOffset; // top offset of image in page int bitDepthAttribute; // Yaroze sprite needs this attribute short clutX; // X Position of clut info short clutY; // Y Position of clut onfo } Costume; Costume CostumeList[MAX_COSTUMES]; int NextCostume = 0; // Next available costume in List // Declare any internal functions used within this manager void LoadTexture ( long address, Costume* NewCostume ); void FindTopLeftOfTexturePage ( GsIMAGE* imageInfo, int*x, int *y, int* u, int *v ); // This function will create x number of costumes. It simply requires // the address of the TIM and how many costumes in the x and y direction // are contained within it. It will return the costume ID of the // first costume it created. // NOTE : This function will load the costumes going from the top left // of the image and loading in the x direction followed by the y direction // eg. given x = 3, y = 2 the costumes ID will be : // 0 1 2 // 3 4 5 // int fwCostumeAdd ( long address, int xNumber, int yNumber ) { Costume StoreCostume; int StoreFirstCostume; int StoreXOffset; int xp, yp; // First we must load the image from main memory into display memory // and store the costume infomation. // NOTE : At this stage we assume we are loading a single costume. // and so therefore we load the costume information into a // temporary costume. LoadTexture ( address, &StoreCostume ); // Now for a little tweaking. We have loaded the whole // image as if it were a single costume // The x and y parameters indicate how many actual costumes // are contained within the image. // Use this information to insert each individual costume // into the Costume List. // Modify the width and height to correspond to the // dimensions of each individual costume. StoreCostume.width = StoreCostume.width / xNumber; StoreCostume.height = StoreCostume.height / yNumber; // Make a note of the x offset of the original costume StoreXOffset = StoreCostume.xOffset; // Remember what the first costume we have added // This is the costume ID that we shall be returning StoreFirstCostume = NextCostume; // Repeat for each costume on the y direction for ( yp= 1; yp <= yNumber; yp++ ) { // Reset the xOffset to the first costume in the // x direction StoreCostume.xOffset = StoreXOffset; // Repeat for each costume in the x direction for ( xp = 1; xp <= xNumber; xp++ ) { // Store the costume information into the // Next available costume in the List CostumeList[NextCostume].tPage = StoreCostume.tPage; CostumeList[NextCostume].pmode = StoreCostume.pmode; CostumeList[NextCostume].width = StoreCostume.width; CostumeList[NextCostume].height = StoreCostume.height; CostumeList[NextCostume].xOffset = StoreCostume.xOffset; CostumeList[NextCostume].yOffset = StoreCostume.yOffset; CostumeList[NextCostume].bitDepthAttribute = StoreCostume.bitDepthAttribute; CostumeList[NextCostume].clutX = StoreCostume.clutX; CostumeList[NextCostume].clutY = StoreCostume.clutY; // Increment our Next available costume NextCostume++; // Shift the costume offset to point to the next // costume in the x direction StoreCostume.xOffset += StoreCostume.width; } // Shift the costume offset to point to the next // costume in the y direction StoreCostume.yOffset += StoreCostume.height; } return (StoreFirstCostume); } // Given a TIM and a costume structure this function will load the // TIM information into Video memory. It will then populate the // costume structure with all the information it requires void LoadTexture ( long address, Costume* NewCostume ) { GsIMAGE imageInfo; RECT rect; RECT rectclut; int texturePageX; int texturePageY; int xOffset; int yOffset; int tPageType; int WidthCompression; // Get the details of the image from the TIM header GsGetTimInfo ( ( u_long *)(address+4), &imageInfo ); // Get the image dimensions rect.x = imageInfo.px; rect.y = imageInfo.py; rect.w = imageInfo.pw; rect.h = imageInfo.ph; // Copy the image into Video Memory LoadImage ( &rect, imageInfo.pixel ); // if the image needs a clut the load it now if ( ( imageInfo.pmode >> 3 ) && 0x01 ) { // Get the clut dimensions rectclut.x = imageInfo.cx; rectclut.y = imageInfo.cy; rectclut.w = imageInfo.cw; rectclut.h = imageInfo.ch; // Copy the clut into Video memory LoadImage ( &rectclut, imageInfo.clut ); } // In order to populate the costume structure we need // the bit depth of the image switch ( imageInfo.pmode ) { case 2: // 16 bit image NewCostume->bitDepthAttribute = (1<<25); WidthCompression = 1; tPageType = 2; NewCostume->clutX = 0; NewCostume->clutY = 0; break; case 8: // 4 bit NewCostume->bitDepthAttribute = 0; WidthCompression = 4; tPageType = 0; NewCostume->clutX = imageInfo.cx; NewCostume->clutY = imageInfo.cy; break; case 9: // 8 bit NewCostume->bitDepthAttribute = (1<<24); WidthCompression = 2; tPageType = 1; NewCostume->clutX = imageInfo.cx; NewCostume->clutY = imageInfo.cy; break; default: printf ( "Only 4,8 and 16 bit modes are supported\n" ); printf ( "You have a pmode of %d\n", imageInfo.pmode ); } // Now we need to store all the information we need // to use the image FindTopLeftOfTexturePage ( &imageInfo, &texturePageX, &texturePageY, &xOffset, &yOffset ); // Given the top left corner of a texture page // get the actual texture page number NewCostume->tPage = GetTPage ( tPageType, 0, texturePageX, texturePageY ); // The width is currently the number of ints. Convert this // width into actual number of pixels NewCostume->width = imageInfo.pw * WidthCompression; NewCostume->height = imageInfo.ph; // The xOffset we calculated is in terms of ints. Convert // this offset based on the bit depth of the texture. NewCostume->xOffset = xOffset * WidthCompression; NewCostume->yOffset = yOffset; // We now must wait for the loading to finish DrawSync(0); } // This function will simply populate a GsSprite structure // with all the information it needs to use a particular costume void fwCostumeApplyToSprite ( GsSPRITE *sprite, int Costume ) { sprite->tpage = CostumeList[Costume].tPage; sprite->w = CostumeList[Costume].width; sprite->h = CostumeList[Costume].height; sprite->mx = sprite->w / 2; sprite->my = sprite->h / 2; sprite->u = CostumeList[Costume].xOffset; sprite->v = CostumeList[Costume].yOffset; sprite->attribute |= CostumeList[Costume].bitDepthAttribute; sprite->cx = CostumeList[Costume].clutX; sprite->cy = CostumeList[Costume].clutY; } // Given a TIM x and y position within the video memory this function // will calculate the x and y offset within a texture page. // NOTE : This function returns the x offset in terms of int // ( ie that the TIM is a 16 bit image ) // NOTE : You may have noticed that this function does not look like // it has been writen by me... Your right... I have taken this out of // one of the supplied Tutorials. // void FindTopLeftOfTexturePage ( GsIMAGE* imageInfo, int*x, int *y, int* u, int *v ) { int testX; int testY; testX = imageInfo->px; testY = imageInfo->py; *u = 0; *v = 0; for ( ;; ) { if ( testX % 64 != 0 ) { testX--; (*u)++; } else { break; } } for ( ;; ) { if ( testY % 256 != 0 ) { testY--; (*v)++; } else { break; } } *x = testX; *y = testY; }