void TCOD_sys_console_to_bitmap(void *vbitmap, int console_width, int console_height, char_t *console_buffer, char_t *prev_console_buffer) { int x,y; sfImage *bitmap=(sfImage *)vbitmap; TCOD_color_t fading_color = TCOD_console_get_fading_color(); static int oldFade=-1; uint8 fade = TCOD_console_get_fade(); static sfShape *rectShape=NULL; if ( ! rectShape ) { rectShape=sfShape_CreateRectangle(0.5f, 0.5f, 0.5f + fontWidth, 0.5f + fontHeight, sfBlack, 0.0f, sfBlack); sfShape_EnableOutline(rectShape, sfFalse); } for (y=0;y<console_height;y++) { for (x=0; x<console_width; x++) { char_t *c=&console_buffer[x+y*console_width]; bool changed=true; if ( changed ) { sfColor b={c->back.r,c->back.g,c->back.b,255}; // background b.r = ((int)b.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255; b.g = ((int)b.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255; b.b = ((int)b.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255; int destx=x*fontWidth; int desty=y*fontHeight; if ( (void *)bitmap == (void *)renderWindow && fullscreen_on ) { destx+=fullscreen_offsetx; desty+=fullscreen_offsety; } sfShape_SetPosition(rectShape,destx+0.5f,desty+0.5f); sfShape_SetColor(rectShape,sfWhite); sfRenderWindow_DrawShape (renderWindow, rectShape); nbBlit++; int srcx,srcy; if ( c->c != ' ') { // foreground int ascii=(int)c->c; sfColor f={c->fore.r,c->fore.g,c->fore.b,255}; f.r = ((int)f.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255; f.g = ((int)f.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255; f.b = ((int)f.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255; if (fontInRow) { srcx = (ascii%fontNbCharHoriz)*fontWidth; srcy = (ascii/fontNbCharHoriz)*fontHeight; } else { srcx = (ascii/fontNbCharVertic)*fontWidth; srcy = (ascii%fontNbCharVertic)*fontHeight; } sfIntRect rect={srcx,srcy,srcx+fontWidth-1,srcy+fontHeight-1}; sfSprite_SetSubRect(charmapSprite,&rect); sfSprite_SetX(charmapSprite,destx); sfSprite_SetY(charmapSprite,desty); sfSprite_SetColor(charmapSprite,f); sfRenderWindow_DrawSprite(renderWindow,charmapSprite); } } } } }
static void TCOD_sys_render(void *vbitmap, int console_width, int console_height, char_t *console_buffer, char_t *prev_console_buffer) { if ( TCOD_ctx.renderer == TCOD_RENDERER_SDL ) { TCOD_sys_console_to_bitmap(vbitmap, console_width, console_height, console_buffer, prev_console_buffer); if ( TCOD_ctx.sdl_cbk ) { TCOD_ctx.sdl_cbk((void *)screen); } SDL_Flip(screen); } oldFade=(int)TCOD_console_get_fade(); if ( any_ascii_updated ) { memset(ascii_updated,0,sizeof(bool)*TCOD_ctx.max_font_chars); any_ascii_updated=false; } }
// render when no font is loaded (happens when using some TCODImage stuff without root console) void TCOD_sys_console_to_bitmap_nocharmap(void *vbitmap, TCOD_console_data_t *con, bool new_font) { int x,y; SDL_Surface *bitmap=(SDL_Surface *)vbitmap; Uint32 sdl_back=0; TCOD_color_t fading_color = TCOD_console_get_fading_color(); int fade = (int)TCOD_console_get_fade(); bool track_changes=(TCOD_old_fade == fade && con->oldbuf); for (y=0;y<con->h;y++) { for (x=0; x<con->w; x++) { SDL_Rect dstRect; bool changed=true; char_t *c=&con->buf[x+y*con->w]; TCOD_bitmap_char_t *bitmap_char=&TCOD_font_chars[c->c]; TCOD_color_t b=TCOD_image_get_pixel(con->backbuf,x,y); if ( c->cf == -1 ) c->cf = bitmap_char->ascii_to_tcod; if ( track_changes ) { TCOD_color_t oldb=TCOD_image_get_pixel(con->oldbackbuf,x,y); changed=false; if ( bitmap_char->updated || b.r != oldb.r || b.g != oldb.g || b.b != oldb.b ) { changed=true; } } if ( changed ) { dstRect.x=x*TCOD_font_width; dstRect.y=y*TCOD_font_height; dstRect.w=TCOD_font_width; dstRect.h=TCOD_font_height; // draw background if ( fade != 255 ) { b.r = ((int)b.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255; b.g = ((int)b.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255; b.b = ((int)b.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255; } sdl_back=SDL_MapRGB(bitmap->format,b.r,b.g,b.b); if ( bitmap == TCOD_screen && TCOD_fullscreen_on ) { dstRect.x+=TCOD_fullscreen_offsetx; dstRect.y+=TCOD_fullscreen_offsety; } SDL_FillRect(bitmap,&dstRect,sdl_back); } } } TCOD_old_fade=fade; }
/* render the console on a surface/texture SDL12 : vbitmap = SDL_Surface SDL2 : vbitmap = SDL_Texture */ static void render(void *vbitmap, int console_width, int console_height, char_t *console_buffer, char_t *prev_console_buffer) { char_t *prev_console_buffer_ptr = prev_console_buffer; if ( TCOD_ctx.renderer == TCOD_RENDERER_SDL ) { TCOD_sys_console_to_bitmap(vbitmap, console_width, console_height, console_buffer, prev_console_buffer_ptr); if ( TCOD_ctx.sdl_cbk ) { TCOD_ctx.sdl_cbk((void *)screen); } SDL_Flip(screen); } #ifndef NO_OPENGL else { TCOD_opengl_render(oldFade, ascii_updated, console_buffer, prev_console_buffer); TCOD_opengl_swap(); } #endif oldFade=(int)TCOD_console_get_fade(); if ( any_ascii_updated ) { memset(ascii_updated,0,sizeof(bool)*TCOD_ctx.max_font_chars); any_ascii_updated=false; } }
bool TCOD_opengl_render( int oldFade, bool *ascii_updated, char_t *console_buffer, char_t *prev_console_buffer) { int x,y,i; int fade = (int)TCOD_console_get_fade(); bool track_changes=(oldFade == fade && prev_console_buffer); char_t *c=console_buffer; char_t *oc=prev_console_buffer; int ascii; /* update opengl data */ /* TODO use function pointers so that libtcod's putchar directly updates opengl data */ for (y=0;y<conheight;y++) { for (x=0; x<conwidth; x++) { bool changed=true; if ( c->cf == -1 ) c->cf = TCOD_ctx.ascii_to_tcod[c->c]; if ( track_changes ) { changed=false; if ( c->dirt || ascii_updated[ c->c ] || c->back.r != oc->back.r || c->back.g != oc->back.g || c->back.b != oc->back.b || c->fore.r != oc->fore.r || c->fore.g != oc->fore.g || c->fore.b != oc->fore.b || c->c != oc->c || c->cf != oc->cf) { changed=true; } } c->dirt=0; if ( changed ) { TCOD_opengl_putchar_ex(x,y,c->cf,c->fore,c->back); } c++;oc++; } } /* check if any of the textures have changed since they were last uploaded */ for( i = 0; i< ConsoleDataEnumSize; i++) { if(dirty[i]) { updateTex((ConsoleDataEnum)i); dirty[i] = false; } } if ( TCOD_ctx.renderer == TCOD_RENDERER_OPENGL ) { /* fixed pipeline for video cards without pixel shader support */ /* draw the background as a single quad */ float texw=(float)conwidth/POTconwidth; float texh=(float)conheight/POTconheight; float fonw=(float)fontwidth/(TCOD_ctx.fontNbCharHoriz*POTfontwidth); float fonh=(float)fontheight/(TCOD_ctx.fontNbCharVertic*POTfontheight); char_t *c; DBGCHECKGL(glBindTexture(GL_TEXTURE_2D, Tex[BackCol])); DBGCHECKGL(glBegin(GL_QUADS); glColor3f(1.0,1.0,1.0); glTexCoord2f( 0.0, 0.0 ); glVertex2i( 0, 0); glTexCoord2f( 0.0, texh); glVertex2i( 0, conheight ); glTexCoord2f( texw, texh ); glVertex2i( conwidth, conheight); glTexCoord2f( texw, 0.0 ); glVertex2i( conwidth, 0 ); glEnd()); /* draw the characters (one quad per cell) */ DBGCHECKGL(glBindTexture(GL_TEXTURE_2D, font_tex)); c=console_buffer; for (y=0;y<conheight;y++) { for (x=0; x<conwidth; x++) { if ( c->c != ' ' ) { TCOD_color_t f=c->fore; TCOD_color_t b=c->back; /* only draw character if foreground color != background color */ if ( f.r != b.r || f.g != b.g || f.b != b.b ) { int srcx,srcy,destx,desty; destx=x;/* *TCOD_font_width; */ desty=y;/* *TCOD_font_height; */ if ( TCOD_ctx.fullscreen ) { destx+=TCOD_ctx.fullscreen_offsetx/TCOD_ctx.font_width; desty+=TCOD_ctx.fullscreen_offsety/TCOD_ctx.font_height; } /* draw foreground */ ascii=c->cf; srcx = (ascii%TCOD_ctx.fontNbCharHoriz); srcy = (ascii/TCOD_ctx.fontNbCharHoriz); glBegin( GL_QUADS ); glColor3f((GLfloat)(f.r/255.0), (GLfloat)(f.g/255.0), (GLfloat)(f.b/255.0)); glTexCoord2f( srcx*fonw, srcy*fonh ); glVertex2i( destx, desty); glTexCoord2f( srcx*fonw, (srcy+1)*fonh ); glVertex2i( destx, desty+1 ); glTexCoord2f( (srcx+1)*fonw, (srcy+1)*fonh ); glVertex2i( destx+1, desty+1 ); glTexCoord2f( (srcx+1)*fonw, srcy*fonh ); glVertex2i( destx+1, desty ); glEnd(); } } c++; } } DBGCHECKGL(glBindTexture(GL_TEXTURE_2D, 0)); } else {
void TCOD_sys_console_to_bitmap(void *vbitmap, int console_width, int console_height, char_t *console_buffer, char_t *prev_console_buffer) { int x,y; SDL_Surface *bitmap=(SDL_Surface *)vbitmap; Uint32 sdl_back=0,sdl_fore=0; TCOD_color_t fading_color = TCOD_console_get_fading_color(); int fade = (int)TCOD_console_get_fade(); bool track_changes=(oldFade == fade && prev_console_buffer); #ifdef USE_SDL_LOCKS if ( SDL_MUSTLOCK( bitmap ) && SDL_LockSurface( bitmap ) < 0 ) return; #endif for (y=0;y<console_height;y++) { for (x=0; x<console_width; x++) { SDL_Rect srcRect,dstRect; bool changed=true; char_t *c=&console_buffer[x+y*console_width]; if ( c->cf == -1 ) c->cf = ascii_to_tcod[c->c]; if ( track_changes ) { char_t *oc=&prev_console_buffer[x+y*console_width]; changed=false; if ( c->dirt || ascii_updated[ c->c ] || c->back.r != oc->back.r || c->back.g != oc->back.g || c->back.b != oc->back.b || c->fore.r != oc->fore.r || c->fore.g != oc->fore.g || c->fore.b != oc->fore.b || c->c != oc->c || c->cf != oc->cf) { changed=true; } } c->dirt=0; if ( changed ) { TCOD_color_t b=c->back; dstRect.x=x*fontWidth; dstRect.y=y*fontHeight; dstRect.w=fontWidth; dstRect.h=fontHeight; // draw background b.r = ((int)b.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255; b.g = ((int)b.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255; b.b = ((int)b.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255; sdl_back=SDL_MapRGB(bitmap->format,b.r,b.g,b.b); if ( bitmap == screen && fullscreen_on ) { dstRect.x+=fullscreen_offsetx; dstRect.y+=fullscreen_offsety; } SDL_FillRect(bitmap,&dstRect,sdl_back); if ( c->c != ' ' ) { // draw foreground //int ascii=fontTcodLayout ? (int)(ascii_to_tcod[c->c]): c->c; int ascii=c->cf; TCOD_color_t *curtext = &charcols[ascii]; bool first = first_draw[ascii]; TCOD_color_t f=c->fore; f.r = ((int)f.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255; f.g = ((int)f.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255; f.b = ((int)f.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255; // only draw character if foreground color != background color if ( ascii_updated[c->c] || f.r != b.r || f.g != b.g || f.b != b.b ) { if ( charmap && charmap->format->Amask == 0 && f.r == fontKeyCol.r && f.g == fontKeyCol.g && f.b == fontKeyCol.b ) { // cannot draw with the key color... if ( f.r < 255 ) f.r++; else f.r--; } if (fontInRow) { srcRect.x = (ascii%fontNbCharHoriz)*fontWidth; srcRect.y = (ascii/fontNbCharHoriz)*fontHeight; } else { srcRect.x = (ascii/fontNbCharVertic)*fontWidth; srcRect.y = (ascii%fontNbCharVertic)*fontHeight; } srcRect.w=fontWidth; srcRect.h=fontHeight; if ( charmap && (first || curtext->r != f.r || curtext->g != f.g || curtext->b!=f.b) ) { // change the character color in the font Uint8 bpp = charmap->format->BytesPerPixel; first_draw[ascii]=false; sdl_fore=SDL_MapRGB(charmap->format,f.r,f.g,f.b) & rgb_mask; *curtext=f; #ifdef USE_SDL_LOCKS if ( SDL_MUSTLOCK(charmap) ) { if ( SDL_LockSurface(charmap) < 0 ) return; } #endif if ( bpp == 4 ) { // 32 bits font : fill the whole character with color Uint32 *pix = (Uint32 *)(((Uint8 *)charmap->pixels)+srcRect.x*bpp + srcRect.y*charmap->pitch); int hdelta=(charmap->pitch - fontWidth*bpp)/4; int h=fontHeight; while (h> 0) { int w=fontWidth; while ( w > 0 ) { (*pix) &= nrgb_mask; (*pix) |= sdl_fore; w--; pix++; } h--; pix += hdelta; } } else { // 24 bits font : fill only non key color pixels Uint32 *pix = (Uint32 *)(((Uint8 *)charmap->pixels)+srcRect.x*bpp + srcRect.y*charmap->pitch); int h=fontHeight; int hdelta=(charmap->pitch - fontWidth*bpp); while (h> 0) { int w=fontWidth; while ( w > 0 ) { if (((*pix) & rgb_mask) != sdl_key ) { (*pix) &= nrgb_mask; (*pix) |= sdl_fore; } w--; pix = (Uint32 *) (((Uint8 *)pix)+3); } h--; pix = (Uint32 *) (((Uint8 *)pix)+hdelta); } } #ifdef USE_SDL_LOCKS if ( SDL_MUSTLOCK(charmap) ) { SDL_UnlockSurface(charmap); } #endif } SDL_BlitSurface(charmap,&srcRect,bitmap,&dstRect); } } } } } #ifdef USE_SDL_LOCKS if ( SDL_MUSTLOCK( bitmap ) ) SDL_UnlockSurface( bitmap ); #endif oldFade=fade; if ( any_ascii_updated ) { memset(ascii_updated,0,sizeof(bool)*TCOD_max_font_chars); any_ascii_updated=false; } }
/* In order to avoid rendering race conditions and the ensuing segmentation * faults, this should only be called when it would normally be and not * specifically to force screen refreshes. To this end, and to avoid * threading complications it takes care of special cases internally. */ static void render(void *vbitmap, int console_width, int console_height, char_t *console_buffer, char_t *prev_console_buffer) { char_t *prev_console_buffer_ptr = prev_console_buffer; if ( TCOD_ctx.renderer == TCOD_RENDERER_SDL ) { int console_width_p = console_width*TCOD_ctx.font_width; int console_height_p = console_height*TCOD_ctx.font_height; /* Make a bitmap of exact rendering size and correct format. */ if (scale_screen == NULL) { int bpp; Uint32 rmask, gmask, bmask, amask; if (SDL_PixelFormatEnumToMasks(SDL_GetWindowPixelFormat(window), &bpp, &rmask, &gmask, &bmask, &amask) == SDL_FALSE) { TCOD_fatal("SDL : failed to create scaling surface : indeterminate window pixel format"); return; } scale_screen=SDL_CreateRGBSurface(SDL_SWSURFACE,console_width_p,console_height_p,bpp,rmask,gmask,bmask,amask); if (scale_screen == NULL) { TCOD_fatal("SDL : failed to create scaling surface"); return; } } else if (clear_screen) { clear_screen=false; SDL_FillRect(scale_screen,0,0); /* Implicitly do complete console redraw, not just tracked changes. */ prev_console_buffer_ptr = NULL; } TCOD_sys_console_to_bitmap(scale_screen, console_width, console_height, console_buffer, prev_console_buffer_ptr); /* Scale the rendered bitmap to the screen, preserving aspect ratio, and blit it. * This data is also used for console coordinate resolution.. */ if (scale_data.last_scale_factor != scale_factor || scale_data.last_scale_xc != scale_xc || scale_data.last_scale_yc != scale_yc || scale_data.last_fullscreen != TCOD_ctx.fullscreen || scale_data.force_recalc) { /* Preserve old value of input variables, to enable recalculation if they change. */ scale_data.last_scale_factor = scale_factor; scale_data.last_scale_xc = scale_xc; scale_data.last_scale_yc = scale_yc; scale_data.last_fullscreen = TCOD_ctx.fullscreen; scale_data.force_recalc = 0; if (scale_data.last_fullscreen) { scale_data.surface_width = TCOD_ctx.actual_fullscreen_width; scale_data.surface_height = TCOD_ctx.actual_fullscreen_height; } else { scale_data.surface_width = console_width_p; scale_data.surface_height = console_height_p; } scale_data.min_scale_factor = MAX((float)console_width_p/scale_data.surface_width, (float)console_height_p/scale_data.surface_height); if (scale_data.min_scale_factor > 1.0f) scale_data.min_scale_factor = 1.0f; /*printf("min_scale_factor %0.3f = MAX(%d/%d, %d/%d)", scale_data.min_scale_factor, console_width_p, scale_data.surface_width, console_height_p, scale_data.surface_height);*/ scale_data.dst_height_width_ratio = (float)scale_data.surface_height/scale_data.surface_width; scale_data.src_proportionate_width = (int)(console_width_p / scale_factor); scale_data.src_proportionate_height = (int)((console_width_p * scale_data.dst_height_width_ratio) / scale_factor); /* Work out how much of the console to copy. */ scale_data.src_x0 = (scale_xc * console_width_p) - (0.5f * scale_data.src_proportionate_width); if (scale_data.src_x0 + scale_data.src_proportionate_width > console_width_p) scale_data.src_x0 = console_width_p - scale_data.src_proportionate_width; if (scale_data.src_x0 < 0) scale_data.src_x0 = 0; scale_data.src_copy_width = scale_data.src_proportionate_width; if (scale_data.src_x0 + scale_data.src_copy_width > console_width_p) scale_data.src_copy_width = console_width_p - scale_data.src_x0; scale_data.src_y0 = (scale_yc * console_height_p) - (0.5f * scale_data.src_proportionate_height); if (scale_data.src_y0 + scale_data.src_proportionate_height > console_height_p) scale_data.src_y0 = console_height_p - scale_data.src_proportionate_height; if (scale_data.src_y0 < 0) scale_data.src_y0 = 0; scale_data.src_copy_height = scale_data.src_proportionate_height; if (scale_data.src_y0 + scale_data.src_copy_height > console_height_p) scale_data.src_copy_height = console_height_p - scale_data.src_y0; scale_data.dst_display_width = (scale_data.src_copy_width * scale_data.surface_width) / scale_data.src_proportionate_width; scale_data.dst_display_height = (scale_data.src_copy_height * scale_data.surface_height) / scale_data.src_proportionate_height; scale_data.dst_offset_x = (scale_data.surface_width - scale_data.dst_display_width)/2; scale_data.dst_offset_y = (scale_data.surface_height - scale_data.dst_display_height)/2; } SDL_RenderClear(renderer); actual_rendering(); SDL_RenderPresent(renderer); } #ifndef NO_OPENGL else { TCOD_opengl_render(oldFade, ascii_updated, console_buffer, prev_console_buffer); TCOD_opengl_swap(); } #endif oldFade=(int)TCOD_console_get_fade(); if ( any_ascii_updated ) { memset(ascii_updated,0,sizeof(bool)*TCOD_ctx.max_font_chars); any_ascii_updated=false; } }
uint8 TCODConsole::getFade() { return TCOD_console_get_fade(); }