SpritePtr CreateStatsSpriteClone( SpritePtr masterSpriteP, short numDigits, JustifyType justification, int fillWithZeros) { StatsStructPtr spriteStructP; SpritePtr newSpriteP; SWError err = kNoError; SW_ASSERT(masterSpriteP != NULL); SW_ASSERT(masterSpriteP->maxFrames >= 10); // Allocate memory for the StatsStruct spriteStructP = (StatsStructPtr)calloc(1,sizeof(StatsStruct)); if (!spriteStructP) { err = kMemoryAllocationError; } if (err == kNoError) { err = SWCloneSprite(masterSpriteP, &newSpriteP, spriteStructP); } if (err == kNoError) { // Set the Sprite's DrawProc to our special digit-drawing DrawProc. newSpriteP->frameDrawProc = StatsItemDrawProc; // Adjust the Sprite's width to match the width of all the digits put together. newSpriteP->drawData->scaledWidth = SW_RECT_WIDTH(newSpriteP->destFrameRect) * numDigits; newSpriteP->drawData->scaledHeight = SW_RECT_HEIGHT(newSpriteP->destFrameRect); SWSetCurrentFrameIndex(newSpriteP, newSpriteP->curFrameIndex); spriteStructP->numDigits = numDigits; spriteStructP->theNum = -1; spriteStructP->justification = justification; spriteStructP->fillWithZeros = fillWithZeros; spriteStructP->drawProc = SWStdSpriteDrawProc; } else { newSpriteP = NULL; } return newSpriteP; }
SWError blitStringToFrame( char *string, TTF_Font *font, int align, int rendering, SDL_Color *textColor, SDL_Color *backColor, FramePtr frameP ) { SWError err = kNoError; char *lineStart, *lineEnd; SDL_Surface *textSurface = NULL, *convertedTextSurface = NULL; int lineSkipHeight = TTF_FontLineSkip( font ); SDL_Rect destRect; int lineWidth; // draw the background. Transparent for solid or blended, // solid bkgnd color for smooth. if( rendering == STRendering_Smooth ) SDL_FillRect( frameP->frameSurfaceP, NULL, SDL_MapRGBA( frameP->frameSurfaceP->format, backColor->r, backColor->g, backColor->b, 0xFF ) ); else SDL_FillRect( frameP->frameSurfaceP, NULL, SDL_MapRGBA( frameP->frameSurfaceP->format, backColor->r, backColor->g, backColor->b, 0x00 ) ); destRect.x = frameP->frameRect.left; destRect.y = frameP->frameRect.top; destRect.w = SW_RECT_WIDTH( frameP->frameRect ); lineStart = string; // render each line, one at a time, and blit them over to our frame // one after another. We have to start at the last line and work // our way to the first, since some characters hang over to the // line below, and we don't want those bits cut off. while( lineStart != NULL && *lineStart != '\0' && destRect.y < frameP->frameRect.bottom && err == kNoError ) { lineEnd = strchr( lineStart, '\n' ); if( lineEnd != NULL ) { // we need to insert a null char temporarily at the end of // this line, so that we can render just this text. *lineEnd = '\0'; } TTF_SizeText( font, lineStart, &lineWidth, NULL ); switch( rendering ) { case STRendering_Solid: textSurface = TTF_RenderText_Solid( font, lineStart, *textColor ); break; case STRendering_Smooth: textSurface = TTF_RenderText_Shaded( font, lineStart, *textColor, *backColor ); break; case STRendering_Blended: textSurface = TTF_RenderText_Blended( font, lineStart, *textColor ); break; } if( textSurface == NULL ) err = kSTTextRenderingError; if( err == kNoError ) { // put things back the way we found them, now that // the text has been rendered if( lineEnd != NULL ) *lineEnd = '\n'; // convert the text surface to the display format, so we can // blit it safely onto frameSurfaceP convertedTextSurface = SDL_ConvertSurface( textSurface, frameP->frameSurfaceP->format, SDL_SWSURFACE ); if( convertedTextSurface == NULL ) err = kSTTextRenderingError; } if( err == kNoError ) { switch( align ) { case STAlign_Left: destRect.x = 0; break; case STAlign_Center: destRect.x = (frameP->frameRect.right / 2) - (lineWidth / 2); break; case STAlign_Right: destRect.x = frameP->frameRect.right - lineWidth; break; } // if we don't unset the SRCALPHA flag, then the dest // surface alpha will remain untouched, and our text // wont show up using a std blit. This is the way SDL // is designed, although it is aknowledged to be // counterintuitive in the docs. if( SDL_SetAlpha( convertedTextSurface, 0, 0xFF ) < 0 ) err = kSTTextRenderingError; if( SDL_SetColorKey( convertedTextSurface, SDL_SRCCOLORKEY, SDL_MapRGBA( convertedTextSurface->format, 0xFF, 0xFF, 0xFF, 0x00 ) ) < 0 ) err = kSTTextRenderingError; } // we use our own function for alpha bending since for // a RGBA to RGBA blit, SDL either leaves the dest alpha // untouched (if SRCALPHA is set), or replaces it completely // with the source alpha (if SRCALPHA is not set). In the first // option the text doesnt show up at all, and in the second hanging // characters such as 'g' and 'j' have their bottoms cut off // when the next line is blit. So we do our own blit pixel-by-pixel, // 'alpha-bending' (taking the max of src/dest alphas) as we go. // FWIK, this is rediculously slow on HW surfaces, but until // somebody comesup with a better solution... if( err == kNoError ) { if( rendering == STRendering_Blended || rendering == STRendering_Solid ) alphaBlendTextSurfaceToFrame( convertedTextSurface, frameP->frameSurfaceP, &destRect ); else { if( err == kNoError ) if( SDL_BlitSurface( convertedTextSurface, NULL, frameP->frameSurfaceP, &destRect ) < 0 ) err = kSTTextRenderingError; } } if( err == kNoError ) { if( lineEnd == NULL ) lineStart = NULL; else lineStart = lineEnd + 1; destRect.y += lineSkipHeight; } if( textSurface ) SDL_FreeSurface( textSurface ); if( convertedTextSurface ) SDL_FreeSurface( convertedTextSurface ); } return err; }
SWError st_CreateStaticText( const char* string, const char* fontPath, int fontSize, SWRect* bounds, int wrap, StaticTextPtr* newStaticTextPP ) { SWError err = kNoError; FramePtr frameP = NULL; StaticTextPtr tempStaticTextP = NULL; *newStaticTextPP = 0; if( ! gSTHasBeenInitialized ) err = kSTHasNotBeenInitedError; if( err == kNoError ) if( strlen( string ) > kMaxStringLength - 1 ) err = kSTStringTooLongError; if( err == kNoError ) if( strlen( fontPath ) > kMaxPathLength - 1 ) err = kSTPathTooLongError; if( err == kNoError ) { tempStaticTextP = malloc( sizeof( StaticTextRec ) ); if( ! tempStaticTextP ) err = kMemoryAllocationError; } if( err == kNoError ) err = SWCreateSprite( (SpritePtr*)&tempStaticTextP, tempStaticTextP, 1 ); if( err == kNoError ) { SWSetSpriteMoveProc( (SpritePtr)tempStaticTextP, handleStaticText ); // make the frame to which we will be copying each line of text err = SWCreateBlankFrame( &frameP, SW_RECT_WIDTH( *bounds ), SW_RECT_HEIGHT( *bounds ), SDL_GetVideoInfo()->vfmt->BitsPerPixel, true ); } if( err == kNoError ) { SWSetSpriteLocation( (SpritePtr)tempStaticTextP, bounds->left, bounds->top ); err = SWAddFrame( (SpritePtr)tempStaticTextP, frameP ); } if( err == kNoError ) { strcpy( tempStaticTextP->string, string ); strcpy( tempStaticTextP->fontPath, fontPath ); tempStaticTextP->fontSize = fontSize; tempStaticTextP->fontStyle = gDefaultStyle; tempStaticTextP->wrap = wrap; tempStaticTextP->bounds = *bounds; tempStaticTextP->align = gDefaultAlign; tempStaticTextP->rendering = gDefaultRendering; tempStaticTextP->textColor = gDefaultTextColor; tempStaticTextP->backColor = gDefaultBackColor; err = SWSetCurrentFrameIndex( (SpritePtr)tempStaticTextP, 0 ); } if( err == kNoError ) err = renderStaticText( tempStaticTextP ); if( err == kNoError ) { SWLockSprite( (SpritePtr)tempStaticTextP ); *newStaticTextPP = tempStaticTextP; } if( err != kNoError ) { // clean up what we can if( tempStaticTextP ) st_DisposeStaticText( &tempStaticTextP ); if( frameP ) SWDisposeFrame( &frameP ); } SWSetStickyIfError( err ); return err; }
void StatsItemDrawProc( FramePtr srcFrameP, FramePtr dstFrameP, SWRect* srcRectP, SWRect* dstRectP) { short n, theDigit, width, index, fillValue; long theNum; char digitArray[10]; // Enough digits for a long StatsStructPtr statsStructP; FramePtr *srcFrameArray; SWRect destRect, srcRect, frameRect, clippedDstRect; SW_ASSERT(gSWCurrentElementDrawData != NULL); statsStructP = (StatsStructPtr)gSWCurrentElementDrawData->parentSpriteP; srcFrameArray = gSWCurrentElementDrawData->parentSpriteP->frameArray; theNum = statsStructP->theNum; if (statsStructP->fillWithZeros) fillValue = 0; else fillValue = -1; // Fill the unused part of the display with either nothing or 0s. for (n=0; n < statsStructP->numDigits; n++) digitArray[n] = fillValue; // Put the number into the digitArray if (theNum >= 0) { if (statsStructP->justification == kLeftJustify) index = GetNumberLength(theNum)-1; else index = statsStructP->numDigits-1; do { // Fill digitArray with the digits from the new number digitArray[index] = theNum%10; // Get the right-most digit index--; theNum /= 10; // Remove the right-most digit } while (theNum > 0 && index >= 0); } destRect = *dstRectP; frameRect = srcFrameArray[0]->frameRect; width = SW_RECT_WIDTH(frameRect); // Expand destRect's left and top to its original size before it was clipped if (srcRectP->top > frameRect.top) destRect.top += frameRect.top - srcRectP->top; if (srcRectP->left > frameRect.left) destRect.left += frameRect.left - srcRectP->left; // The destRect's width and height should be the size of one digit. destRect.bottom = destRect.top + SW_RECT_HEIGHT(frameRect); destRect.right = destRect.left + width; // Draw the number for (index = 0; index < statsStructP->numDigits; index++) { theDigit = digitArray[index]; if (theDigit >= 0) { srcFrameP = srcFrameArray[theDigit]; srcRect = srcFrameP->frameRect; // Clip each digit with the dstRect passed to this drawProc. clippedDstRect = destRect; SW_CLIP_DST_AND_SRC_RECT(clippedDstRect, srcRect, (*dstRectP)); // Set the sprite's location (used by hardware drawprocs) gSWCurrentElementDrawData->horizLoc = clippedDstRect.left; gSWCurrentElementDrawData->vertLoc = clippedDstRect.top; if (gSWCurrentSpriteWorld != NULL) { gSWCurrentElementDrawData->horizLoc += gSWCurrentSpriteWorld->visScrollRect.left; gSWCurrentElementDrawData->vertLoc += gSWCurrentSpriteWorld->visScrollRect.top; } // Draw the digit (*statsStructP->drawProc)(srcFrameP, dstFrameP, &srcRect, &clippedDstRect); } destRect.left += width; destRect.right += width; } }