add sierra lite dithering 32bpp or 24bpp to 16bpp for all images, reloadable media or scrolling list if requested by field dithering in xml

Signed-off-by: Vincent-FK <vincent.buso@funkey-project.com>
This commit is contained in:
Vincent-FK 2020-02-25 12:48:48 +01:00
parent 69e0a51dd2
commit 3576503dc3
11 changed files with 184 additions and 30 deletions

View File

@ -19,10 +19,13 @@
#include "../../Utility/Log.h"
#include <SDL/SDL_image.h>
Image::Image(std::string file, std::string altFile, Page &p, float scaleX, float scaleY)
Image::Image(std::string file, std::string altFile, Page &p, float scaleX, float scaleY, bool dithering)
: Component(p)
, texture_(NULL)
, texture_prescaled_(NULL)
, ditheringAuthorized_(dithering)
, needDithering_(false)
, imgBitsPerPx_(32)
, file_(file)
, altFile_(altFile)
, scaleX_(scaleX)
@ -39,6 +42,7 @@ Image::~Image()
void Image::freeGraphicsMemory()
{
Component::freeGraphicsMemory();
//printf("freeGraphicsMemory: %s\n", file_.c_str());
SDL_LockMutex(SDL::getMutex());
if (texture_ != NULL)
@ -64,7 +68,7 @@ void Image::allocateGraphicsMemory()
SDL_LockMutex(SDL::getMutex());
/* Load image */
SDL_Surface *img_tmp = NULL;
SDL_Surface * img_tmp = NULL;
//printf("Loading image: %s\n", file_.c_str());
img_tmp = IMG_Load(file_.c_str());
if (!img_tmp && altFile_ != "")
@ -76,6 +80,11 @@ void Image::allocateGraphicsMemory()
if (img_tmp != NULL)
{
/* Check if dithering needed */
imgBitsPerPx_ = img_tmp->format->BitsPerPixel;
if( imgBitsPerPx_ > 16 && ditheringAuthorized_){
needDithering_ = true;
}
/* Convert to RGB 32bit if necessary */
if(img_tmp->format->BitsPerPixel != 32){
@ -126,7 +135,8 @@ void Image::draw()
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){
if(cache_scaling_needed && imgBitsPerPx_ > 16 && ditheringAuthorized_){
needDithering_ = true;
texture_prescaled_ = SDL::zoomSurface(texture_, NULL, &rect);
if(texture_prescaled_ == NULL){
printf("ERROR in %s - Could not create texture_prescaled_\n", __func__);
@ -139,11 +149,23 @@ void Image::draw()
}
}
/* Surface to display */
SDL_Surface * surfaceToRender = NULL;
if(use_prescaled && texture_prescaled_ != NULL){
SDL::renderCopy(texture_prescaled_, baseViewInfo.Alpha, NULL, &rect, baseViewInfo);
surfaceToRender = texture_prescaled_;
}
else{
SDL::renderCopy(texture_, baseViewInfo.Alpha, NULL, &rect, baseViewInfo);
surfaceToRender = texture_;
}
/* Dithering */
if(needDithering_){
//printf("Dither: %s\n", file_.c_str());
SDL::ditherSurface32bppTo16Bpp(surfaceToRender);
needDithering_ = false;
}
/* Render */
SDL::renderCopy(surfaceToRender, baseViewInfo.Alpha, NULL, &rect, baseViewInfo);
}
}

View File

@ -22,7 +22,7 @@
class Image : public Component
{
public:
Image(std::string file, std::string altFile, Page &p, float scaleX, float scaleY);
Image(std::string file, std::string altFile, Page &p, float scaleX, float scaleY, bool dithering);
virtual ~Image();
void freeGraphicsMemory();
void allocateGraphicsMemory();
@ -35,4 +35,7 @@ protected:
std::string altFile_;
float scaleX_;
float scaleY_;
bool ditheringAuthorized_;
bool needDithering_;
int imgBitsPerPx_;
};

View File

@ -18,7 +18,7 @@
#include "../../Utility/Log.h"
#include <fstream>
Image * ImageBuilder::CreateImage(std::string path, Page &p, std::string name, float scaleX, float scaleY)
Image * ImageBuilder::CreateImage(std::string path, Page &p, std::string name, float scaleX, float scaleY, bool dithering)
{
Image *image = NULL;
std::vector<std::string> extensions;
@ -36,7 +36,7 @@ Image * ImageBuilder::CreateImage(std::string path, Page &p, std::string name, f
//printf(" findMatchingFile, prefix = %s, file = %s\n", prefix.c_str(), file.c_str());
if(Utils::findMatchingFile(prefix, extensions, file))
{
image = new Image(file, "", p, scaleX, scaleY);
image = new Image(file, "", p, scaleX, scaleY, dithering);
}
return image;

View File

@ -24,5 +24,5 @@
class ImageBuilder
{
public:
Image * CreateImage(std::string path, Page &p, std::string name, float scaleX, float scaleY);
Image * CreateImage(std::string path, Page &p, std::string name, float scaleX, float scaleY, bool dithering);
};

View File

@ -28,7 +28,7 @@
#include <vector>
#include <iostream>
ReloadableMedia::ReloadableMedia(Configuration &config, bool systemMode, bool layoutMode, bool commonMode, bool menuMode, std::string type, Page &p, int displayOffset, bool isVideo, Font *font, float scaleX, float scaleY)
ReloadableMedia::ReloadableMedia(Configuration &config, bool systemMode, bool layoutMode, bool commonMode, bool menuMode, std::string type, Page &p, int displayOffset, bool isVideo, Font *font, float scaleX, float scaleY, bool dithering)
: Component(p)
, config_(config)
, systemMode_(systemMode)
@ -39,6 +39,7 @@ ReloadableMedia::ReloadableMedia(Configuration &config, bool systemMode, bool la
, videoInst_(NULL)
, isVideo_(isVideo)
, FfntInst_(font)
, ditheringAuthorized_(dithering)
, textFallback_(false)
, imageFallback_(false)
, imageAndTextPadding_(0)
@ -424,7 +425,7 @@ void ReloadableMedia::reloadTexture( bool previousItem )
ImageBuilder imageBuild;
imagePath = Utils::combinePath(Configuration::absolutePath, "collections", collectionName );
imagePath = Utils::combinePath( imagePath, "system_artwork" );
loadedComponent_ = imageBuild.CreateImage( imagePath, page, std::string("fallback"), scaleX_, scaleY_ );
loadedComponent_ = imageBuild.CreateImage( imagePath, page, std::string("fallback"), scaleX_, scaleY_, ditheringAuthorized_ );
}
// if image and artwork was not specified, fall back to displaying text
@ -492,7 +493,7 @@ Component *ReloadableMedia::findComponent(std::string collection, std::string ty
}
else
{
component = imageBuild.CreateImage(imagePath, page, basename, scaleX_, scaleY_);
component = imageBuild.CreateImage(imagePath, page, basename, scaleX_, scaleY_, ditheringAuthorized_);
}
return component;

View File

@ -27,7 +27,7 @@ class Image;
class ReloadableMedia : public Component
{
public:
ReloadableMedia(Configuration &config, bool systemMode, bool layoutMode, bool commonMode, bool menuMode, std::string type, Page &page, int displayOffset, bool isVideo, Font *font, float scaleX, float scaleY);
ReloadableMedia(Configuration &config, bool systemMode, bool layoutMode, bool commonMode, bool menuMode, std::string type, Page &page, int displayOffset, bool isVideo, Font *font, float scaleX, float scaleY, bool dithering);
virtual ~ReloadableMedia();
void update(float dt);
void draw();
@ -52,6 +52,7 @@ private:
IVideo *videoInst_;
bool isVideo_;
Font *FfntInst_;
bool ditheringAuthorized_;
bool imageAndText_;
float imageAndTextPadding_;
bool textFallback_;

View File

@ -48,7 +48,8 @@ ScrollingList::ScrollingList( Configuration &c,
float scaleY,
Font *font,
std::string layoutKey,
std::string imageType )
std::string imageType ,
bool dithering)
: Component( p )
, horizontalScroll( false )
, layoutMode_( layoutMode )
@ -69,6 +70,7 @@ ScrollingList::ScrollingList( Configuration &c,
, fontInst_( font )
, layoutKey_( layoutKey )
, imageType_( imageType )
, ditheringAuthorized_( dithering )
, items_( NULL )
{
}
@ -672,7 +674,7 @@ bool ScrollingList::allocateTexture( unsigned int index, Item *item )
else
config_.getMediaPropertyAbsolutePath( collectionName, imageType_, false, imagePath );
}
t = imageBuild.CreateImage( imagePath, page, names[n], scaleX_, scaleY_ );
t = imageBuild.CreateImage( imagePath, page, names[n], scaleX_, scaleY_, ditheringAuthorized_ );
// check sub-collection path for art
if ( !t && !commonMode_ )
@ -686,7 +688,7 @@ bool ScrollingList::allocateTexture( unsigned int index, Item *item )
{
config_.getMediaPropertyAbsolutePath( item->collectionInfo->name, imageType_, false, imagePath );
}
t = imageBuild.CreateImage( imagePath, page, names[n], scaleX_, scaleY_ );
t = imageBuild.CreateImage( imagePath, page, names[n], scaleX_, scaleY_, ditheringAuthorized_ );
}
}
@ -714,19 +716,19 @@ bool ScrollingList::allocateTexture( unsigned int index, Item *item )
config_.getMediaPropertyAbsolutePath( item->name, imageType_, true, imagePath );
}
}
t = imageBuild.CreateImage( imagePath, page, imageType_, scaleX_, scaleY_ );
t = imageBuild.CreateImage( imagePath, page, imageType_, scaleX_, scaleY_, ditheringAuthorized_ );
}
// check rom directory path for art
if ( !t ){
t = imageBuild.CreateImage( item->filepath, page, imageType_, scaleX_, scaleY_ );
t = imageBuild.CreateImage( item->filepath, page, imageType_, scaleX_, scaleY_, ditheringAuthorized_ );
}
// Image fallback
if ( !t && imageType_.compare(std::string("null"))){
imagePath = Utils::combinePath(Configuration::absolutePath, "collections", collectionName );
imagePath = Utils::combinePath( imagePath, "system_artwork" );
t = imageBuild.CreateImage( imagePath, page, std::string("fallback"), scaleX_, scaleY_ );
t = imageBuild.CreateImage( imagePath, page, std::string("fallback"), scaleX_, scaleY_, ditheringAuthorized_ );
}
if ( !t )

View File

@ -41,7 +41,8 @@ public:
float scaleY,
Font *font,
std::string layoutKey,
std::string imageType );
std::string imageType,
bool dithering);
ScrollingList( const ScrollingList &copy );
virtual ~ScrollingList( );
@ -124,6 +125,7 @@ private:
Font *fontInst_;
std::string layoutKey_;
std::string imageType_;
bool ditheringAuthorized_;
std::vector<Item *> *items_;
std::vector<Component *> components_;

View File

@ -429,6 +429,15 @@ bool PageBuilder::buildComponents(xml_node<> *layout, Page *page)
{
xml_attribute<> *src = componentXml->first_attribute("src");
xml_attribute<> *idXml = componentXml->first_attribute("id");
xml_attribute<> *ditheringXml = componentXml->first_attribute("dithering");
bool dithering =false;
if (ditheringXml &&
(Utils::toLower(ditheringXml->value()) == "true" ||
Utils::toLower(ditheringXml->value()) == "yes"))
{
dithering = true;
}
int id = -1;
if (idXml)
@ -449,7 +458,7 @@ bool PageBuilder::buildComponents(xml_node<> *layout, Page *page)
std::string altImagePath;
altImagePath = Utils::combinePath(Configuration::absolutePath, "layouts", layoutName, std::string(src->value()));
Image *c = new Image(imagePath, altImagePath, *page, scaleX_, scaleY_);
Image *c = new Image(imagePath, altImagePath, *page, scaleX_, scaleY_, dithering);
c->setId( id );
xml_attribute<> *menuScrollReload = componentXml->first_attribute("menuScrollReload");
if (menuScrollReload &&
@ -780,10 +789,20 @@ void PageBuilder::loadReloadableImages(xml_node<> *layout, std::string tagName,
}
}
}
else
else //ReloadableMedia
{
Font *font = addFont(componentXml, NULL);
c = new ReloadableMedia(config_, systemMode, layoutMode, commonMode, menuMode, type->value(), *page, selectedOffset, (tagName == "reloadableVideo"), font, scaleX_, scaleY_);
xml_attribute<> *ditheringXml = componentXml->first_attribute("dithering");
bool dithering =false;
if (ditheringXml &&
(Utils::toLower(ditheringXml->value()) == "true" ||
Utils::toLower(ditheringXml->value()) == "yes"))
{
dithering = true;
}
c = new ReloadableMedia(config_, systemMode, layoutMode, commonMode, menuMode, type->value(), *page, selectedOffset, (tagName == "reloadableVideo"), font, scaleX_, scaleY_, dithering);
c->setId( id );
xml_attribute<> *menuScrollReload = componentXml->first_attribute("menuScrollReload");
if (menuScrollReload &&
@ -1025,6 +1044,7 @@ ScrollingList * PageBuilder::buildMenu(xml_node<> *menuXml, Page &page)
xml_attribute<> *scrollTimeXml = menuXml->first_attribute("scrollTime");
xml_attribute<> *scrollAccelerationXml = menuXml->first_attribute("scrollAcceleration");
xml_attribute<> *scrollOrientationXml = menuXml->first_attribute("orientation");
xml_attribute<> *ditheringXml = menuXml->first_attribute("dithering");
if(menuTypeXml)
{
@ -1065,7 +1085,15 @@ ScrollingList * PageBuilder::buildMenu(xml_node<> *menuXml, Page &page)
// on default, text will be rendered to the menu. Preload it into cache.
Font *font = addFont(itemDefaults, NULL);
menu = new ScrollingList(config_, page, layoutMode, commonMode, scaleX_, scaleY_, font, layoutKey, imageType);
bool dithering =false;
if (ditheringXml &&
(Utils::toLower(ditheringXml->value()) == "true" ||
Utils::toLower(ditheringXml->value()) == "yes"))
{
dithering = true;
}
menu = new ScrollingList(config_, page, layoutMode, commonMode, scaleX_, scaleY_, font, layoutKey, imageType, dithering);
if(scrollTimeXml)
{

View File

@ -20,7 +20,22 @@
#include "Utility/Log.h"
#include <SDL/SDL_mixer.h>
//#include <SDL/SDL_rotozoom.h>
#include <SDL/SDL_gfxBlitFunc.h>
//#include <SDL/SDL_gfxBlitFunc.h>
/* Basic math */
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
/* Get 16bit closest color */
#define CLOSEST_RB(c) (MIN(c+4,0xff) >> 3 << 3)
#define CLOSEST_G(c) (MIN(c+2,0xff) >> 2 << 2)
/* RGB8888 */
#define RGB32BIT(a, r, g, b) ((a<<24) | (r<<16) | (g<<8) | b)
#define GET_A_32BIT(c) ((c & 0xff000000) >> 24)
#define GET_R_32BIT(c) ((c & 0x00ff0000) >> 16)
#define GET_G_32BIT(c) ((c & 0x0000ff00) >> 8)
#define GET_B_32BIT(c) (c & 0x000000ff)
//SDL_Window *SDL::window_ = NULL;
@ -353,6 +368,90 @@ void SDL::SDL_Rotate_270(SDL_Surface * src, SDL_Surface * dst){
}
/* Dithering 32bpp RGB Surface
*
* error diffusion with "Filter Lite" also called "Sierra lite" method
*
*/
void SDL::ditherSurface32bppTo16Bpp(SDL_Surface * src_surface){
/* Vars */
int x, y;
uint8_t r_old, g_old, b_old;
uint8_t r_new, g_new, b_new;
int r_error, g_error, b_error;
uint32_t cur_px;
/* Sanity check */
if(src_surface->format->BitsPerPixel != 32){
printf("Error: src_surface is %dBpp while dst_surface is not 32\n", src_surface->format->BitsPerPixel);
return;
}
/* Loop for dithering */
for (y=0; y<src_surface->h; y++){
for (x=0; x < src_surface->w; x++){
/* Get old and new rgb values of current pixel */
cur_px = *((uint32_t*)src_surface->pixels + (y)*src_surface->w + (x));
r_old = GET_R_32BIT(cur_px);
g_old = GET_G_32BIT(cur_px);
b_old = GET_B_32BIT(cur_px);
r_new = CLOSEST_RB(r_old);
g_new = CLOSEST_G(g_old);
b_new = CLOSEST_RB(b_old);
/* Set new pixel value */
*((uint32_t*)src_surface->pixels + (y)*src_surface->w + (x)) = RGB32BIT(GET_A_32BIT(cur_px), r_new, g_new, b_new);
/* Get errors */
r_error = r_old - r_new;
g_error = g_old - g_new;
b_error = b_old - b_new;
/* Right pixel */
if(x + 1 < src_surface->w){
cur_px = *((uint32_t*)src_surface->pixels + (y)*src_surface->w + (x+1));
r_old = GET_R_32BIT(cur_px);
g_old = GET_G_32BIT(cur_px);
b_old = GET_B_32BIT(cur_px);
*((uint32_t*)src_surface->pixels + (y)*src_surface->w + (x+1)) =
RGB32BIT( GET_A_32BIT(cur_px),
MAX(MIN((int)r_old + (r_error>>1), 0xff), 0),
MAX(MIN((int)g_old + (g_error>>1), 0xff), 0),
MAX(MIN((int)b_old + (b_error>>1), 0xff), 0) );
}
/* Bottom pixel */
if(y + 1 < src_surface->h){
cur_px = *((uint32_t*)src_surface->pixels + (y+1)*src_surface->w + (x));
r_old = GET_R_32BIT(cur_px);
g_old = GET_G_32BIT(cur_px);
b_old = GET_B_32BIT(cur_px);
*((uint32_t*)src_surface->pixels + (y+1)*src_surface->w + (x)) =
RGB32BIT( GET_A_32BIT(cur_px),
MAX(MIN((int)r_old + (r_error>>2), 0xff), 0),
MAX(MIN((int)g_old + (g_error>>2), 0xff), 0),
MAX(MIN((int)b_old + (b_error>>2), 0xff), 0) );
}
/* Bottom left pixel */
if( x > 0 && y + 1 < src_surface->h){
cur_px = *((uint32_t*)src_surface->pixels + (y+1)*src_surface->w + (x-1));
r_old = GET_R_32BIT(cur_px);
g_old = GET_G_32BIT(cur_px);
b_old = GET_B_32BIT(cur_px);
*((uint32_t*)src_surface->pixels + (y+1)*src_surface->w + (x-1)) =
RGB32BIT( GET_A_32BIT(cur_px),
MAX(MIN((int)r_old + (r_error>>2), 0xff), 0),
MAX(MIN((int)g_old + (g_error>>2), 0xff), 0),
MAX(MIN((int)b_old + (b_error>>2), 0xff), 0) );
}
}
}
}
// Copy virtual window to HW window and Flip display
void SDL::renderAndFlipWindow( )
{

View File

@ -33,13 +33,11 @@ class SDL
public:
static bool initialize( Configuration &config );
static bool deInitialize( );
//static SDL_Renderer *getRenderer( );
static SDL_mutex *getMutex( );
//static SDL_Window *getWindow( );
static SDL_Surface *getWindow( );
static void renderAndFlipWindow( );
//static bool renderCopy( SDL_Texture *texture, float alpha, SDL_Rect *src, SDL_Rect *dest, ViewInfo &viewInfo );
static SDL_Surface * zoomSurface(SDL_Surface *surface_ptr, SDL_Rect *src_rect_origin, SDL_Rect *dst_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( )
{
@ -56,8 +54,6 @@ public:
static void SDL_Rotate_270(SDL_Surface * dst, SDL_Surface * src);
private:
//static SDL_Window *window_;
//static SDL_Renderer *renderer_;
static Uint32 get_pixel32( SDL_Surface *surface, int x, int y );
static void put_pixel32( SDL_Surface *surface, int x, int y, Uint32 pixel );
static SDL_Surface * flip_surface( SDL_Surface *surface, int flags );