/** * Draw one overlay * @param it Overlay info */ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { int idx, len, width; ObjectStruct *obj; AnimData *sprite; byte *mask; switch (it->type) { // color sprite case 0: if (g_cine->_objectTable[it->objIdx].frame < 0) { return; } sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; memcpy(mask, sprite->mask(), len); remaskSprite(mask, it); drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask); delete[] mask; break; // game message case 2: if (it->objIdx >= g_cine->_messageTable.size()) { return; } _messageLen += g_cine->_messageTable[it->objIdx].size(); drawMessage(g_cine->_messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); waitForPlayerClick = 1; break; // action failure message case 3: idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3); len = strlen(failureMessages[idx]); _messageLen += len; width = 6 * len + 20; width = width > 300 ? 300 : width; drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, 4); waitForPlayerClick = 1; break; // bitmap case 4: assert(it->objIdx < NUM_MAX_OBJECT); obj = &g_cine->_objectTable[it->objIdx]; if (obj->frame < 0) { return; } if (!g_cine->_animDataTable[obj->frame].data()) { return; } fillSprite(*obj); break; } }
Font::Font( const char *inFileName, int inCharSpacing, int inSpaceWidth, char inFixedWidth, double inScaleFactor, int inFixedCharWidth ) : mScaleFactor( inScaleFactor ), mCharSpacing( inCharSpacing ), mSpaceWidth( inSpaceWidth ), mFixedWidth( inFixedWidth ) { Image *spriteImage = readTGAFile( inFileName ); if( spriteImage != NULL ) { int width = spriteImage->getWidth(); int height = spriteImage->getHeight(); int numPixels = width * height; rgbaColor *spriteRGBA = new rgbaColor[ numPixels ]; unsigned char *spriteBytes = RGBAImage::getRGBABytes( spriteImage ); delete spriteImage; for( int i=0; i<numPixels; i++ ) { for( int b=0; b<4; b++ ) { spriteRGBA[i].bytes[b] = spriteBytes[ i*4 + b ]; } } delete [] spriteBytes; // use corner color as transparency // copy red channel into other channels // (ignore other channels, even for transparency) spriteRGBA[0].comp.a = 0; unsigned char tr; tr = spriteRGBA[0].comp.r; for( int i=0; i<numPixels; i++ ) { unsigned char r = spriteRGBA[i].comp.r; if( r == tr ) { // matches corner r spriteRGBA[i].comp.a = 0; } spriteRGBA[i].comp.g = r; spriteRGBA[i].comp.b = r; } mSpriteWidth = width / 16; mSpriteHeight = height / 16; if( inFixedCharWidth == 0 ) { mCharBlockWidth = mSpriteWidth; } else { mCharBlockWidth = inFixedCharWidth; } int pixelsPerChar = mSpriteWidth * mSpriteHeight; for( int i=0; i<256; i++ ) { int yOffset = ( i / 16 ) * mSpriteHeight; int xOffset = ( i % 16 ) * mSpriteWidth; rgbaColor *charRGBA = new rgbaColor[ pixelsPerChar ]; for( int y=0; y<mSpriteHeight; y++ ) { for( int x=0; x<mSpriteWidth; x++ ) { int imageIndex = (y + yOffset) * width + x + xOffset; int charIndex = y * mSpriteWidth + x; charRGBA[ charIndex ] = spriteRGBA[ imageIndex ]; } } // don't bother consuming texture ram for blank sprites char allTransparent = true; for( int p=0; p<pixelsPerChar && allTransparent; p++ ) { if( charRGBA[ p ].comp.a != 0 ) { allTransparent = false; } } if( !allTransparent ) { // convert into an image Image *charImage = new Image( mSpriteWidth, mSpriteHeight, 4, false ); for( int c=0; c<4; c++ ) { double *chan = charImage->getChannel(c); for( int p=0; p<pixelsPerChar; p++ ) { chan[p] = charRGBA[p].bytes[c] / 255.0; } } mSpriteMap[i] = fillSprite( charImage ); delete charImage; } else { mSpriteMap[i] = NULL; } if( mFixedWidth ) { mCharLeftEdgeOffset[i] = 0; mCharWidth[i] = mCharBlockWidth; } else if( allTransparent ) { mCharLeftEdgeOffset[i] = 0; mCharWidth[i] = mSpriteWidth; } else { // implement pseudo-kerning int farthestLeft = mSpriteWidth; int farthestRight = 0; char someInk = false; for( int y=0; y<mSpriteHeight; y++ ) { for( int x=0; x<mSpriteWidth; x++ ) { unsigned char r = charRGBA[ y * mSpriteWidth + x ].comp.r; if( r > 0 ) { someInk = true; if( x < farthestLeft ) { farthestLeft = x; } if( x > farthestRight ) { farthestRight = x; } } } } if( ! someInk ) { mCharLeftEdgeOffset[i] = 0; mCharWidth[i] = mSpriteWidth; } else { mCharLeftEdgeOffset[i] = farthestLeft; mCharWidth[i] = farthestRight - farthestLeft + 1; } } delete [] charRGBA; } delete [] spriteRGBA; } }