From 2eb437708de5822641fa673cd236c25d3b84155d Mon Sep 17 00:00:00 2001 From: Vincent-FK Date: Tue, 31 Mar 2020 01:35:48 +0200 Subject: [PATCH] BUG correction: keep_aspect_ratio does bot work for images. Now we can set the containerWidth and containerHeight params for automatic cropping Signed-off-by: Vincent-FK --- RetroFE/Source/Graphics/Component/Battery.cpp | 2 +- RetroFE/Source/Graphics/Component/Image.cpp | 85 ++++++----- RetroFE/Source/SDL.cpp | 135 +++++++++++++----- RetroFE/Source/SDL.h | 4 +- 4 files changed, 158 insertions(+), 68 deletions(-) diff --git a/RetroFE/Source/Graphics/Component/Battery.cpp b/RetroFE/Source/Graphics/Component/Battery.cpp index 3cef160..7ae047b 100755 --- a/RetroFE/Source/Graphics/Component/Battery.cpp +++ b/RetroFE/Source/Graphics/Component/Battery.cpp @@ -442,7 +442,7 @@ void Battery::draw() if(scaling_needed){ cache_scaling_needed = (texture_prescaled_ == NULL)?true:(texture_prescaled_->w != rect.w || texture_prescaled_->h != rect.h); if(cache_scaling_needed){ - texture_prescaled_ = SDL::zoomSurface(texture_, NULL, &rect); + texture_prescaled_ = SDL::zoomSurface(texture_, NULL, &rect, NULL); if(texture_prescaled_ == NULL){ printf("ERROR in %s - Could not create texture_prescaled_\n", __func__); use_prescaled = false; diff --git a/RetroFE/Source/Graphics/Component/Image.cpp b/RetroFE/Source/Graphics/Component/Image.cpp index d74b3a3..67f0528 100755 --- a/RetroFE/Source/Graphics/Component/Image.cpp +++ b/RetroFE/Source/Graphics/Component/Image.cpp @@ -131,43 +131,62 @@ void Image::draw() rect.h = static_cast(baseViewInfo.ScaledHeight()); rect.w = static_cast(baseViewInfo.ScaledWidth()); - /* Cache scaling */ - scaling_needed = rect.w!=0 && rect.h!=0 && (texture_->w != rect.w || texture_->h != rect.h); - if(scaling_needed){ - cache_scaling_needed = (texture_prescaled_ == NULL)?true:(texture_prescaled_->w != rect.w || texture_prescaled_->h != rect.h); - if(cache_scaling_needed){ - texture_prescaled_ = SDL::zoomSurface(texture_, NULL, &rect); - if(texture_prescaled_ == NULL){ - printf("ERROR in %s - Could not create texture_prescaled_\n", __func__); - use_prescaled = false; - } - if(imgBitsPerPx_ > 16 && ditheringAuthorized_){ - needDithering_ = true; - } - } + /* Cropping needed ? */ + bool cropping_needed = false; + SDL_Rect rect_cropping; + if ( (baseViewInfo.ContainerWidth > 0 && baseViewInfo.ContainerHeight > 0) && + (baseViewInfo.ContainerWidth != rect.w || baseViewInfo.ContainerHeight != rect.h)){ + cropping_needed = true; + rect_cropping.x = (rect.w - baseViewInfo.ContainerWidth)/2; + rect_cropping.y = (rect.h - baseViewInfo.ContainerHeight)/2; + rect_cropping.w = baseViewInfo.ContainerWidth; + rect_cropping.h = baseViewInfo.ContainerHeight; + /*printf("\nrect = [{%d, %d} %dx%d], rect_cropping = [{%d, %d} %dx%d]\n", + rect.x, rect.y, rect.w, rect.h, + rect_cropping.x, rect_cropping.y, rect_cropping.w, rect_cropping.h);*/ + } - if(texture_prescaled_ != NULL){ - use_prescaled = true; - } + /* Cache scaling */ + scaling_needed = (rect.w!=0 && rect.h!=0) && (texture_->w != rect.w || texture_->h != rect.h); + if(scaling_needed){ + cache_scaling_needed = (texture_prescaled_ == NULL)?true: + ((!cropping_needed && (texture_prescaled_->w != rect.w || texture_prescaled_->h != rect.h)) || + (cropping_needed && (texture_prescaled_->w != rect_cropping.w || texture_prescaled_->h != rect_cropping.h) )); + if(cache_scaling_needed){ + /*printf("\nComputing prescaling and cropping in Image.cpp %s\n", cropping_needed?"and cropping":"");*/ + texture_prescaled_ = SDL::zoomSurface(texture_, NULL, &rect, cropping_needed?&rect_cropping:NULL); + if(texture_prescaled_ == NULL){ + printf("ERROR in %s - Could not create texture_prescaled_\n", __func__); + use_prescaled = false; } + if(imgBitsPerPx_ > 16 && ditheringAuthorized_){ + needDithering_ = true; + } + } - /* Surface to display */ - SDL_Surface * surfaceToRender = NULL; - if(use_prescaled && texture_prescaled_ != NULL){ - surfaceToRender = texture_prescaled_; - } - else{ - surfaceToRender = texture_; - } + if(texture_prescaled_ != NULL){ + use_prescaled = true; + } + } - /* Dithering */ - if(needDithering_){ - //printf("Dither: %s\n", file_.c_str()); - SDL::ditherSurface32bppTo16Bpp(surfaceToRender); - needDithering_ = false; - } + /* Surface to display */ + SDL_Surface * surfaceToRender = NULL; + if(use_prescaled && texture_prescaled_ != NULL){ + surfaceToRender = texture_prescaled_; + } + else{ + surfaceToRender = texture_; + } - /* Render */ - SDL::renderCopy(surfaceToRender, baseViewInfo.Alpha, NULL, &rect, baseViewInfo); + /* Dithering */ + if(needDithering_){ + //printf("Dither: %s\n", file_.c_str()); + SDL::ditherSurface32bppTo16Bpp(surfaceToRender); + needDithering_ = false; + } + + /* Render */ + //printf("image render\n"); + SDL::renderCopy(surfaceToRender, baseViewInfo.Alpha, NULL, &rect, baseViewInfo); } } diff --git a/RetroFE/Source/SDL.cpp b/RetroFE/Source/SDL.cpp index fbd4160..25f82b4 100755 --- a/RetroFE/Source/SDL.cpp +++ b/RetroFE/Source/SDL.cpp @@ -549,7 +549,7 @@ SDL_Surface * SDL::flip_surface( SDL_Surface *surface, int flags ) } /// Nearest neighboor optimized with possible out of screen coordinates (for cropping) -SDL_Surface * SDL::zoomSurface(SDL_Surface *src_surface, SDL_Rect *src_rect_origin, SDL_Rect *dst_rect){ +SDL_Surface * SDL::zoomSurface(SDL_Surface *src_surface, SDL_Rect *src_rect_origin, SDL_Rect *dst_rect, SDL_Rect *post_cropping_rect){ /* Declare vars */ int x_ratio; @@ -564,7 +564,6 @@ SDL_Surface * SDL::zoomSurface(SDL_Surface *src_surface, SDL_Rect *src_rect_orig printf("ERROR in %s, sanity check\n", __func__); return NULL; } - /* Sanity checks */ if( src_rect_origin == NULL){ srcRect.x = 0; srcRect.y = 0; @@ -593,6 +592,14 @@ SDL_Surface * SDL::zoomSurface(SDL_Surface *src_surface, SDL_Rect *src_rect_orig printf("ERROR src_rect->y (%d) > src_rect->h(%d) \n", srcRect.y, srcRect.h); return NULL; } + if( post_cropping_rect != NULL ){ + if( post_cropping_rect->w > dst_rect->w){ + post_cropping_rect->w = dst_rect->w; + } + if( post_cropping_rect->h > dst_rect->h){ + post_cropping_rect->h = dst_rect->h; + } + } /*printf("zoomSurface: src_surface->w = %d, src_surface->h = %d, src_surface->BytesPerPixel = %d, src_rect = {%d, %d, %d, %d}, dst_rect = {%d, %d, %d, %d}\n", src_surface->w, src_surface->h, src_surface->format->BytesPerPixel, src_rect->x, src_rect->y, src_rect->w, src_rect->h, dst_rect->x, dst_rect->y, dst_rect->w, dst_rect->h);*/ @@ -601,7 +608,7 @@ SDL_Surface * SDL::zoomSurface(SDL_Surface *src_surface, SDL_Rect *src_rect_orig x_ratio = (int)((srcRect.w <<16) / dst_rect->w); y_ratio = (int)((srcRect.h <<16) / dst_rect->h); - /* Create new output surface */ + /* Create dst surface */ SDL_Surface *dst_surface = SDL_CreateRGBSurface(src_surface->flags, dst_rect->w, dst_rect->h, src_surface->format->BitsPerPixel, @@ -612,31 +619,62 @@ SDL_Surface * SDL::zoomSurface(SDL_Surface *src_surface, SDL_Rect *src_rect_orig } /* Columns iterations */ - for (i = 0; i < dst_surface->h; i++) + for (i = 0; i < dst_surface->h; i++) + { + + /* Get current lines in src and dst surfaces */ + uint8_t* t = ( (uint8_t*) dst_surface->pixels + (i*dst_surface->w)*dst_surface->format->BytesPerPixel ); + y2 = ((i*y_ratio)>>16); + uint8_t* p = ( (uint8_t*) src_surface->pixels + ((y2+srcRect.y)*src_surface->w)*src_surface->format->BytesPerPixel ); + rat = srcRect.x << 16; + + /* Lines iterations */ + for (j = 0; j < dst_surface->w; j++) { - /* Get current lines in src and dst surfaces */ - uint8_t* t = ( (uint8_t*) dst_surface->pixels + (i*dst_surface->w)*dst_surface->format->BytesPerPixel ); - y2 = ((i*y_ratio)>>16); - uint8_t* p = ( (uint8_t*) src_surface->pixels + ((y2+srcRect.y)*src_surface->w)*src_surface->format->BytesPerPixel ); - rat = srcRect.x << 16; + /* Get current pixel in src surface */ + x2 = (rat>>16); - /* Lines iterations */ - for (j = 0; j < dst_surface->w; j++) - { + /* Copy src pixel in dst surface */ + //printf("dst_pix_off = %d, x2=%d, y2=%d, p[%d] = %d\n", t-(uint8_t*)dst_surface->pixels, x2, y2, x2, p[x2*src_surface->format->BytesPerPixel]); + memcpy(t, p+x2*src_surface->format->BytesPerPixel, dst_surface->format->BytesPerPixel); + t += dst_surface->format->BytesPerPixel; - /* Get current pixel in src surface */ - x2 = (rat>>16); - - /* Copy src pixel in dst surface */ - //printf("dst_pix_off = %d, x2=%d, y2=%d, p[%d] = %d\n", t-(uint8_t*)dst_surface->pixels, x2, y2, x2, p[x2*src_surface->format->BytesPerPixel]); - memcpy(t, p+x2*src_surface->format->BytesPerPixel, dst_surface->format->BytesPerPixel); - t += dst_surface->format->BytesPerPixel; - - /* Update x position in source surface */ - rat += x_ratio; - } + /* Update x position in source surface */ + rat += x_ratio; } + } + + /* Post cropping */ + if(post_cropping_rect != NULL){ + /* Save prev dst_surface ptr */ + SDL_Surface *prev_dst_surface = dst_surface; + + /* Create dst surface */ + dst_surface = SDL_CreateRGBSurface(src_surface->flags, + post_cropping_rect->w, post_cropping_rect->h, + src_surface->format->BitsPerPixel, + src_surface->format->Rmask, src_surface->format->Gmask, + src_surface->format->Bmask, src_surface->format->Amask); + if(dst_surface == NULL){ + printf("ERROR in %s, cannot create dst_surface for post cropping: %s\n", __func__, SDL_GetError()); + dst_surface = prev_dst_surface; + } + else{ + /*printf("dst_surface is being cropped. prev_dst_surface(%dx%d) -> dst_surface(%dx%d)!!!!!\n", + prev_dst_surface->w, prev_dst_surface->h, dst_surface->w, dst_surface->h); + printf("post_cropping_rect [{%d,%d} %dx%d]\n", + post_cropping_rect->x, post_cropping_rect->y, post_cropping_rect->w, post_cropping_rect->h);*/ + + /* Copy cropped surface */ + if(SDL_BlitSurface(prev_dst_surface, post_cropping_rect, dst_surface, NULL)){ + printf("ERROR in %s, cannot blit previous dst_surface for post cropping: %s\n", __func__, SDL_GetError()); + } + + /* Free previous surface */ + SDL_FreeSurface(prev_dst_surface); + } + } /* Return new zoomed surface */ return dst_surface; @@ -705,13 +743,18 @@ bool SDL::renderCopy( SDL_Surface *texture, float alpha, SDL_Rect *src, SDL_Rect dstRectCopy.h = dstRect.h; - /*printf("before viewinfo remniement -> srcRectCopy->w = %d, srcRectCopy->h = %d, dstRectCopy->w = %d, dstRectCopy->h = %d, viewInfo->ContainerWidth = %f, viewInfo->ContainerHeight = %f\n", - srcRectCopy.w, srcRectCopy.h, dstRectCopy.w, dstRectCopy.h, viewInfo.ContainerWidth, viewInfo.ContainerHeight);*/ + /*printf("before viewinfo remniement -> srcRect->w = %d, srcRect->h = %d, dstRectCopy->w = %d, dstRectCopy->h = %d, viewInfo->ContainerWidth = %f, viewInfo->ContainerHeight = %f\n", + srcRect.w, srcRect.h, dstRectCopy.w, dstRectCopy.h, viewInfo.ContainerWidth, viewInfo.ContainerHeight);*/ +#if 0 // If a container has been defined, limit the display to the container boundaries. if ( viewInfo.ContainerWidth > 0 && viewInfo.ContainerHeight > 0 && dstRectCopy.w > 0 && dstRectCopy.h > 0 ) { + if(viewInfo.ContainerX <= 0) + viewInfo.ContainerX = dstRectCopy.x; + if(viewInfo.ContainerY <= 0) + viewInfo.ContainerY = dstRectCopy.y; // Correct if the image falls to the left of the container if ( dstRect.x < viewInfo.ContainerX ) @@ -745,14 +788,44 @@ bool SDL::renderCopy( SDL_Surface *texture, float alpha, SDL_Rect *src, SDL_Rect srcRect.w = static_cast( dstRect.w * scaleX ); srcRect.h = static_cast( dstRect.h * scaleY ); + /*printf("viewInfo->ContainerWidth = %f, viewInfo->ContainerHeight = %f\n", viewInfo.ContainerWidth, viewInfo.ContainerHeight); + printf("before viewinfo remaniement -> srcRectCopy = [{%d, %d} %dx%d] ---> srcRect = [{%d, %d} %dx%d]\n", + srcRectCopy.x, srcRectCopy.y, srcRectCopy.w, srcRectCopy.h, srcRect.x, srcRect.y, srcRect.w, srcRect.h); + printf("before viewinfo remaniement -> dstRectCopy = [{%d, %d} %dx%d] ---> dstRect = [{%d, %d} %dx%d]\n\n", + dstRectCopy.x, dstRectCopy.y, dstRectCopy.w, dstRectCopy.h, dstRect.x, dstRect.y, dstRect.w, dstRect.h);*/ } +#endif + + /* Cropping needed ? */ + bool cropping_needed = false; + SDL_Rect rect_cropping; + /*if(viewInfo.ContainerWidth > 0 && viewInfo.ContainerHeight > 0) + printf("Testing if cropping needed ? dst_rect = [{%d, %d} %dx%d]\n", + dstRect.x, dstRect.y, dstRect.w, dstRect.h);*/ + if ( (viewInfo.ContainerWidth > 0 && viewInfo.ContainerHeight > 0) && + (viewInfo.ContainerWidth != dstRect.w || viewInfo.ContainerHeight != dstRect.h) ){ + cropping_needed = true; + rect_cropping.x = (dstRect.w - viewInfo.ContainerWidth)/2; + rect_cropping.y = (dstRect.h - viewInfo.ContainerHeight)/2; + rect_cropping.w = viewInfo.ContainerWidth; + rect_cropping.h = viewInfo.ContainerHeight; + dstRect.x += rect_cropping.x; + dstRect.y += rect_cropping.y; + /*printf("cropping needed in sdl ?srcRect = [{%d, %d} %dx%d], rect_cropping = [{%d, %d} %dx%d]\n", + srcRect.x, srcRect.y, srcRect.w, srcRect.h, + rect_cropping.x, rect_cropping.y, rect_cropping.w, rect_cropping.h);*/ + } /* Scaling */ -#define WITH_SCALING -#ifdef WITH_SCALING - scaling_needed = !dstRect.w==0 && !dstRect.h==0 && (srcRect.w != dstRect.w || srcRect.h != dstRect.h); + scaling_needed = (dstRect.w != 0 && dstRect.h!=0) && + ((!cropping_needed && (srcRect.w != dstRect.w || srcRect.h != dstRect.h)) || + (cropping_needed && (srcRect.w != rect_cropping.w || srcRect.h != rect_cropping.h) )); if(scaling_needed){ - texture_zoomed = zoomSurface(texture, &srcRect, &dstRect); + /*printf("Scaling needed in %s\n", __func__); + printf("Scaling needed in sdl ?srcRect = [{%d, %d} %dx%d], dst_rect = [{%d, %d} %dx%d]\n", + srcRect.x, srcRect.y, srcRect.w, srcRect.h, + dstRect.x, dstRect.y, cropping_needed?rect_cropping.w:dstRect.w, cropping_needed?rect_cropping.h:dstRect.h);*/ + texture_zoomed = zoomSurface(texture, &srcRect, &dstRect, cropping_needed?&rect_cropping:NULL); if(texture_zoomed == NULL){ printf("ERROR in %s - Could not create texture_zoomed\n", __func__); return false; @@ -761,7 +834,6 @@ bool SDL::renderCopy( SDL_Surface *texture, float alpha, SDL_Rect *src, SDL_Rect surface_to_blit = texture_zoomed; } } -#endif //WITH_SCALING @@ -817,9 +889,6 @@ bool SDL::renderCopy( SDL_Surface *texture, float alpha, SDL_Rect *src, SDL_Rect if(texture_zoomed) SDL_FreeSurface(texture_zoomed); - /* Reset viewInfo */ - viewInfo.ContainerWidth = -1; - viewInfo.ContainerHeight = -1; diff --git a/RetroFE/Source/SDL.h b/RetroFE/Source/SDL.h index a0bcfd7..bb0f47e 100755 --- a/RetroFE/Source/SDL.h +++ b/RetroFE/Source/SDL.h @@ -24,6 +24,8 @@ //Flip flags #define FLIP_VERTICAL 1 #define FLIP_HORIZONTAL 2 +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) class Configuration; @@ -36,7 +38,7 @@ public: static SDL_mutex *getMutex( ); static SDL_Surface *getWindow( ); static void renderAndFlipWindow( ); - static SDL_Surface * zoomSurface(SDL_Surface *surface_ptr, SDL_Rect *src_rect_origin, SDL_Rect *dst_rect); + static SDL_Surface * zoomSurface(SDL_Surface *surface_ptr, SDL_Rect *src_rect_origin, SDL_Rect *dst_rect, SDL_Rect *post_cropping_rect); static void ditherSurface32bppTo16Bpp(SDL_Surface *src_surface); static bool renderCopy( SDL_Surface *texture, float alpha, SDL_Rect *src, SDL_Rect *dest, ViewInfo &viewInfo ); static int getWindowWidth( )