I encountered a problem with text rendering in my application. I discovered that when changing the window height (winHeight), the text from the texture starts to flicker slightly only in the height position. I am looking for a solution that ensures stable text positioning regardless of the window size. Could you advise me on what kind of error I might be looking for in the code?
// API functions
Sub *sub_createWindow( int width, int height, const char *title, const char *color )
{
setlocale( LC_ALL, "en_US.UTF-8" );
Sub *sub = malloc( sizeof( Sub ) );
if( !sub )
{
fprintf( stderr, "Memory allocation failed for Sub structure.\n" );
return NULL;
}
memset( sub, 0, sizeof( Sub ) );
sub->winWidth = width;
sub->winHeight = height;
sub->background = color;
if( SDL_Init( SDL_INIT_VIDEO ) != 0 )
{
fprintf( stderr, "Unable to initialize SDL: %s\n", SDL_GetError() );
free( sub );
return NULL;
}
if( TTF_Init() == -1 )
{
fprintf( stderr, "Unable to initialize SDL_ttf: %s\n", TTF_GetError() );
SDL_Quit();
free( sub );
return NULL;
}
sub->window = SDL_CreateWindow( title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE );
if( !sub->window )
{
fprintf( stderr, "Could not create window: %s\n", SDL_GetError() );
SDL_Quit();
free( sub );
return NULL;
}
sub->renderer = SDL_CreateRenderer( sub->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
if( !sub->renderer )
{
fprintf( stderr, "Could not create renderer: %s\n", SDL_GetError() );
SDL_DestroyWindow( sub->window );
SDL_Quit();
free( sub );
return NULL;
}
sub->fontFixed = TTF_OpenFont( "9x18.pcf.gz", 18 );
if( !sub->fontFixed )
{
fprintf( stderr, "Failed to load font Fixed: %s\n", TTF_GetError() );
SDL_DestroyRenderer( sub->renderer );
SDL_DestroyWindow( sub->window );
TTF_Quit();
SDL_Quit();
free( sub );
return NULL;
}
/**/
sub->fontWidth = 9;
sub->fontHeight = 18;
sub->fontDescent = 4;
SDL_SetWindowMinimumSize( sub->window, sub->fontWidth, sub->fontHeight );
sub->numLines = sub->winWidth * sub->winHeight;
sub->textTextures = ( SDL_Texture ** ) malloc( sub->numLines * sizeof( SDL_Texture * ) );
for( int i = 0; i < sub->numLines; i++ )
{
sub->textTextures[ i ] = NULL;
}
return sub;
}
void sub_destroyWindow( Sub *sub )
{
if( sub )
{
if( sub->textTextures )
{
for( int i = 0; i < sub->numLines; i++ )
{
if( sub->textTextures[ i ] != NULL )
{
SDL_DestroyTexture( sub->textTextures[ i ] );
sub->textTextures[ i ] = NULL;
}
}
free( sub->textTextures );
sub->textTextures = NULL;
}
if( sub->fontFixed != NULL )
{
TTF_CloseFont( sub->fontFixed );
sub->fontFixed = NULL;
}
if( sub->renderer != NULL )
{
SDL_DestroyRenderer( sub->renderer );
sub->renderer = NULL;
}
if( sub->window != NULL )
{
SDL_DestroyWindow( sub->window );
sub->window = NULL;
}
TTF_Quit();
SDL_Quit();
free( sub );
sub = NULL;
}
}
void sub_beginDraw( Sub *sub )
{
if( sub->texturesNeedUpdate )
{
for( int i = 0; i < sub->numLines; i++ )
{
if( sub->textTextures[ i ] != NULL )
{
SDL_DestroyTexture( sub->textTextures[ i ] );
sub->textTextures[ i ] = NULL;
}
}
sub->numLines = sub->winWidth * sub->winHeight;
sub->textTextures = ( SDL_Texture ** ) malloc( sub->numLines * sizeof( SDL_Texture * ) );
for( int i = 0; i < sub->numLines; i++ )
{
sub->textTextures[ i ] = NULL;
}
sub->texturesNeedUpdate = F;
}
SDL_Color bgColor = { 255, 255, 255, 255 };
if( sub->background && strlen( sub->background ) > 0 )
{
bgColor = sub_hexToColor( sub->background );
}
SDL_SetRenderDrawColor( sub->renderer, bgColor.r, bgColor.g, bgColor.b, bgColor.a );
SDL_RenderClear( sub->renderer );
}
void sub_endDraw( Sub *sub )
{
SDL_RenderPresent( sub->renderer );
}
void sub_drawTextFixed( Sub *sub, int col, int row, const wchar_t *string, const char *colorString )
{
int x = col * sub->fontWidth;
int y = row * sub->fontHeight;
SDL_Color bgColor = { 255, 255, 255, 255 };
SDL_Color fgColor = { 0, 0, 0, 255 };
if( colorString && strlen( colorString ) > 0 )
{
const char *separator = strchr( colorString, '/' );
if( separator && ( separator - colorString == 6 ) && strlen( separator + 1 ) == 6 )
{
char bgColorStr[ 7 ];
strncpy( bgColorStr, colorString, 6 );
bgColorStr[ 6 ] = '\0';
bgColor = sub_hexToColor( bgColorStr );
fgColor = sub_hexToColor( separator + 1 );
}
}
size_t len = wcslen( string );
if( len == 0 )
{
SDL_Rect rect = { x, y, sub->fontWidth, sub->fontHeight };
SDL_SetRenderDrawColor( sub->renderer, bgColor.r, bgColor.g, bgColor.b, bgColor.a );
SDL_RenderFillRect( sub->renderer, &rect );
return;
}
// Drawing a background for text
SDL_Rect rect = { x, y, sub->fontWidth * len, sub->fontHeight };
SDL_SetRenderDrawColor( sub->renderer, bgColor.r, bgColor.g, bgColor.b, bgColor.a );
SDL_RenderFillRect( sub->renderer, &rect );
// Buffering texture for a given line if it doesn't already exist
if( sub->textTextures[ row ] == NULL )
{
size_t utf8Len = len * 4 + 1;
char *utf8Text = ( char * ) malloc( utf8Len );
if( utf8Text )
{
size_t result = wcstombs( utf8Text, string, utf8Len );
if( result == ( size_t ) -1 )
{
printf( "Error converting wide string to multibyte string.\n" );
free( utf8Text );
return;
}
// Rendering text surface in UTF-8
SDL_Surface *textSurface = TTF_RenderUTF8_Shaded( sub->fontFixed, utf8Text, fgColor, bgColor );
if( textSurface )
{
sub->textTextures[ row ] = SDL_CreateTextureFromSurface( sub->renderer, textSurface );
SDL_FreeSurface(textSurface);
}
else
{
printf( "Error rendering string: %s\n", TTF_GetError() );
}
free( utf8Text );
}
}
// Render the cached texture, if any
if( sub->textTextures[ row ] )
{
SDL_Rect textRect = { x, y, 0, 0 };
SDL_QueryTexture( sub->textTextures[ row ], NULL, NULL, &textRect.w, &textRect.h );
SDL_RenderCopy( sub->renderer, sub->textTextures[ row ], NULL, &textRect );
}
}
int sub_procEvent( Sub *sub )
{
SDL_Event event;
if( SDL_WaitEvent( &event ) )
{
do
{
switch( event.type )
{
case SDL_QUIT:
return SDL_QUIT;
case SDL_KEYDOWN:
return event.key.keysym.sym;
case SDL_WINDOWEVENT:
if( event.window.event == SDL_WINDOWEVENT_RESIZED )
{
int newWidth;
int newHeight;
SDL_GetWindowSize( sub->window, &newWidth, &newHeight );
sub->winWidth = newWidth;
sub->winHeight = newHeight;
// Mark textures for re-creation
sub->texturesNeedUpdate = T;
return 0;
}
break;
default:
break;
}
}
while( SDL_PollEvent( &event ) );
}
return 0;
}