-Added ability to use cubic interpolation on image resize (little more quality on non-po2 resizing)

-Added ability for exporter to shrink images to non-integer values. Helps if you want to convert your game artwork from 1080->720 or similar
This commit is contained in:
Juan Linietsky 2015-10-01 16:25:36 -03:00
parent 0840303a9c
commit e055247b17
8 changed files with 501 additions and 393 deletions

View File

@ -400,6 +400,102 @@ Image::Format Image::get_format() const{
return format; return format;
} }
static double _bicubic_interp_kernel( double x ) {
x = ABS(x);
double bc = 0;
if ( x <= 1 )
bc = ( 1.5 * x - 2.5 ) * x * x + 1;
else if ( x < 2 )
bc = ( ( -0.5 * x + 2.5 ) * x - 4 ) * x + 2;
return bc;
}
template<int CC>
static void _scale_cubic(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
// get source image size
int width = p_src_width;
int height = p_src_height;
double xfac = (double) width / p_dst_width;
double yfac = (double) height / p_dst_height;
// coordinates of source points and cooefficiens
double ox, oy, dx, dy, k1, k2;
int ox1, oy1, ox2, oy2;
// destination pixel values
// width and height decreased by 1
int ymax = height - 1;
int xmax = width - 1;
// temporary pointer
for ( int y = 0; y < p_dst_height; y++ ) {
// Y coordinates
oy = (double) y * yfac - 0.5f;
oy1 = (int) oy;
dy = oy - (double) oy1;
for ( int x = 0; x < p_dst_width; x++ ) {
// X coordinates
ox = (double) x * xfac - 0.5f;
ox1 = (int) ox;
dx = ox - (double) ox1;
// initial pixel value
uint8_t *dst=p_dst + (y*p_dst_width+x)*CC;
double color[CC];
for(int i=0;i<CC;i++) {
color[i]=0;
}
for ( int n = -1; n < 3; n++ ) {
// get Y cooefficient
k1 = _bicubic_interp_kernel( dy - (double) n );
oy2 = oy1 + n;
if ( oy2 < 0 )
oy2 = 0;
if ( oy2 > ymax )
oy2 = ymax;
for ( int m = -1; m < 3; m++ ) {
// get X cooefficient
k2 = k1 * _bicubic_interp_kernel( (double) m - dx );
ox2 = ox1 + m;
if ( ox2 < 0 )
ox2 = 0;
if ( ox2 > xmax )
ox2 = xmax;
// get pixel of original image
const uint8_t *p = p_src + (oy2 * p_src_width + ox2)*CC;
for(int i=0;i<CC;i++) {
color[i]+=p[i]*k2;
}
}
}
for(int i=0;i<CC;i++) {
dst[i]=CLAMP(Math::fast_ftoi(color[i]),0,255);
}
}
}
}
template<int CC> template<int CC>
static void _scale_bilinear(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { static void _scale_bilinear(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
@ -559,6 +655,17 @@ void Image::resize( int p_width, int p_height, Interpolation p_interpolation ) {
} }
} break; } break;
case INTERPOLATE_CUBIC: {
switch(get_format_pixel_size(format)) {
case 1: _scale_cubic<1>(r_ptr,w_ptr,width,height,p_width,p_height); break;
case 2: _scale_cubic<2>(r_ptr,w_ptr,width,height,p_width,p_height); break;
case 3: _scale_cubic<3>(r_ptr,w_ptr,width,height,p_width,p_height); break;
case 4: _scale_cubic<4>(r_ptr,w_ptr,width,height,p_width,p_height); break;
}
} break;
} }

View File

@ -91,6 +91,7 @@ public:
INTERPOLATE_NEAREST, INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR, INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
/* INTERPOLATE GAUSS */ /* INTERPOLATE GAUSS */
}; };

View File

@ -1420,12 +1420,12 @@ EditorImportExport::ImageAction EditorImportExport::get_export_image_action() co
return image_action; return image_action;
} }
void EditorImportExport::set_export_image_shrink(int p_shrink) { void EditorImportExport::set_export_image_shrink(float p_shrink) {
image_shrink=p_shrink; image_shrink=p_shrink;
} }
int EditorImportExport::get_export_image_shrink() const{ float EditorImportExport::get_export_image_shrink() const{
return image_shrink; return image_shrink;
} }
@ -1496,12 +1496,12 @@ bool EditorImportExport::image_export_group_get_make_atlas(const StringName& p_e
return image_groups[p_export_group].make_atlas; return image_groups[p_export_group].make_atlas;
} }
void EditorImportExport::image_export_group_set_shrink(const StringName& p_export_group,int p_amount){ void EditorImportExport::image_export_group_set_shrink(const StringName& p_export_group,float p_amount){
ERR_FAIL_COND(!image_groups.has(p_export_group)); ERR_FAIL_COND(!image_groups.has(p_export_group));
image_groups[p_export_group].shrink=p_amount; image_groups[p_export_group].shrink=p_amount;
} }
int EditorImportExport::image_export_group_get_shrink(const StringName& p_export_group) const{ float EditorImportExport::image_export_group_get_shrink(const StringName& p_export_group) const{
ERR_FAIL_COND_V(!image_groups.has(p_export_group),1); ERR_FAIL_COND_V(!image_groups.has(p_export_group),1);
return image_groups[p_export_group].shrink; return image_groups[p_export_group].shrink;

View File

@ -252,7 +252,7 @@ protected:
ImageAction action; ImageAction action;
bool make_atlas; bool make_atlas;
float lossy_quality; float lossy_quality;
int shrink; float shrink;
}; };
Vector<Ref<EditorExportPlugin> > export_plugins; Vector<Ref<EditorExportPlugin> > export_plugins;
@ -260,7 +260,7 @@ protected:
Map<String,int> by_idx; Map<String,int> by_idx;
ImageAction image_action; ImageAction image_action;
float image_action_compress_quality; float image_action_compress_quality;
int image_shrink; float image_shrink;
Set<String> image_formats; Set<String> image_formats;
ExportFilter export_filter; ExportFilter export_filter;
@ -310,8 +310,8 @@ public:
void set_export_image_action(ImageAction p_action); void set_export_image_action(ImageAction p_action);
ImageAction get_export_image_action() const; ImageAction get_export_image_action() const;
void set_export_image_shrink(int p_shrink); void set_export_image_shrink(float p_shrink);
int get_export_image_shrink() const; float get_export_image_shrink() const;
void set_export_image_quality(float p_quality); void set_export_image_quality(float p_quality);
float get_export_image_quality() const; float get_export_image_quality() const;
@ -326,8 +326,8 @@ public:
ImageAction image_export_group_get_image_action(const StringName& p_export_group) const; ImageAction image_export_group_get_image_action(const StringName& p_export_group) const;
void image_export_group_set_make_atlas(const StringName& p_export_group,bool p_make); void image_export_group_set_make_atlas(const StringName& p_export_group,bool p_make);
bool image_export_group_get_make_atlas(const StringName& p_export_group) const; bool image_export_group_get_make_atlas(const StringName& p_export_group) const;
void image_export_group_set_shrink(const StringName& p_export_group,int p_amount); void image_export_group_set_shrink(const StringName& p_export_group,float p_amount);
int image_export_group_get_shrink(const StringName& p_export_group) const; float image_export_group_get_shrink(const StringName& p_export_group) const;
void image_export_group_set_lossy_quality(const StringName& p_export_group,float p_quality); void image_export_group_set_lossy_quality(const StringName& p_export_group,float p_quality);
float image_export_group_get_lossy_quality(const StringName& p_export_group) const; float image_export_group_get_lossy_quality(const StringName& p_export_group) const;

View File

@ -828,7 +828,7 @@ Error EditorTextureImportPlugin::import(const String& p_path, const Ref<Resource
} }
Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink) { Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,float shrink) {
if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) { if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
@ -866,7 +866,7 @@ Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &textur
int orig_w=image.get_width(); int orig_w=image.get_width();
int orig_h=image.get_height(); int orig_h=image.get_height();
image.resize(orig_w/shrink,orig_h/shrink); image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC);
texture->create_from_image(image,tex_flags); texture->create_from_image(image,tex_flags);
texture->set_size_override(Size2(orig_w,orig_h)); texture->set_size_override(Size2(orig_w,orig_h));
@ -926,7 +926,7 @@ Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &textur
int orig_h=image.get_height(); int orig_h=image.get_height();
if (shrink>1) { if (shrink>1) {
image.resize(orig_w/shrink,orig_h/shrink); image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC);
texture->create_from_image(image,tex_flags); texture->create_from_image(image,tex_flags);
texture->set_size_override(Size2(orig_w,orig_h)); texture->set_size_override(Size2(orig_w,orig_h));
} }
@ -987,7 +987,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
tex_flags|=Texture::FLAG_ANISOTROPIC_FILTER; tex_flags|=Texture::FLAG_ANISOTROPIC_FILTER;
print_line("path: "+p_path+" flags: "+itos(tex_flags)); print_line("path: "+p_path+" flags: "+itos(tex_flags));
int shrink=1; float shrink=1;
if (from->has_option("shrink")) if (from->has_option("shrink"))
shrink=from->get_option("shrink"); shrink=from->get_option("shrink");

View File

@ -70,7 +70,7 @@ private:
static EditorTextureImportPlugin *singleton[MODE_MAX]; static EditorTextureImportPlugin *singleton[MODE_MAX];
//used by other importers such as mesh //used by other importers such as mesh
Error _process_texture_data(Ref<ImageTexture> &texture, int format, float quality, int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink); Error _process_texture_data(Ref<ImageTexture> &texture, int format, float quality, int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,float shrink);
void compress_image(EditorExportPlatform::ImageCompression p_mode,Image& image,bool p_smaller); void compress_image(EditorExportPlatform::ImageCompression p_mode,Image& image,bool p_smaller);
public: public:

View File

@ -1156,7 +1156,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
image_shrink = memnew( SpinBox ); image_shrink = memnew( SpinBox );
image_shrink->set_min(1); image_shrink->set_min(1);
image_shrink->set_max(8); image_shrink->set_max(8);
image_shrink->set_step(1); image_shrink->set_step(0.1);
image_vb->add_margin_child("Shrink All Images:",image_shrink); image_vb->add_margin_child("Shrink All Images:",image_shrink);
sections->add_child(image_vb); sections->add_child(image_vb);
@ -1237,7 +1237,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
group_shrink->set_min(1); group_shrink->set_min(1);
group_shrink->set_max(8); group_shrink->set_max(8);
group_shrink->set_val(1); group_shrink->set_val(1);
group_shrink->set_step(1); group_shrink->set_step(0.001);
group_options->add_margin_child("Shrink By:",group_shrink); group_options->add_margin_child("Shrink By:",group_shrink);
group_shrink->connect("value_changed",this,"_group_changed"); group_shrink->connect("value_changed",this,"_group_changed");