-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:
parent
0840303a9c
commit
e055247b17
107
core/image.cpp
107
core/image.cpp
@ -400,6 +400,102 @@ Image::Format Image::get_format() const{
|
||||
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>
|
||||
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;
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,7 @@ public:
|
||||
|
||||
INTERPOLATE_NEAREST,
|
||||
INTERPOLATE_BILINEAR,
|
||||
INTERPOLATE_CUBIC,
|
||||
/* INTERPOLATE GAUSS */
|
||||
};
|
||||
|
||||
|
@ -1420,12 +1420,12 @@ EditorImportExport::ImageAction EditorImportExport::get_export_image_action() co
|
||||
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;
|
||||
}
|
||||
|
||||
int EditorImportExport::get_export_image_shrink() const{
|
||||
float EditorImportExport::get_export_image_shrink() const{
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
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));
|
||||
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);
|
||||
return image_groups[p_export_group].shrink;
|
||||
|
@ -252,7 +252,7 @@ protected:
|
||||
ImageAction action;
|
||||
bool make_atlas;
|
||||
float lossy_quality;
|
||||
int shrink;
|
||||
float shrink;
|
||||
};
|
||||
|
||||
Vector<Ref<EditorExportPlugin> > export_plugins;
|
||||
@ -260,7 +260,7 @@ protected:
|
||||
Map<String,int> by_idx;
|
||||
ImageAction image_action;
|
||||
float image_action_compress_quality;
|
||||
int image_shrink;
|
||||
float image_shrink;
|
||||
Set<String> image_formats;
|
||||
|
||||
ExportFilter export_filter;
|
||||
@ -310,8 +310,8 @@ public:
|
||||
void set_export_image_action(ImageAction p_action);
|
||||
ImageAction get_export_image_action() const;
|
||||
|
||||
void set_export_image_shrink(int p_shrink);
|
||||
int get_export_image_shrink() const;
|
||||
void set_export_image_shrink(float p_shrink);
|
||||
float get_export_image_shrink() const;
|
||||
|
||||
void set_export_image_quality(float p_quality);
|
||||
float get_export_image_quality() const;
|
||||
@ -326,8 +326,8 @@ public:
|
||||
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);
|
||||
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);
|
||||
int image_export_group_get_shrink(const StringName& p_export_group) const;
|
||||
void image_export_group_set_shrink(const StringName& p_export_group,float p_amount);
|
||||
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);
|
||||
float image_export_group_get_lossy_quality(const StringName& p_export_group) const;
|
||||
|
||||
|
@ -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) {
|
||||
@ -866,7 +866,7 @@ Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &textur
|
||||
|
||||
int orig_w=image.get_width();
|
||||
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->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();
|
||||
|
||||
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->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;
|
||||
|
||||
print_line("path: "+p_path+" flags: "+itos(tex_flags));
|
||||
int shrink=1;
|
||||
float shrink=1;
|
||||
if (from->has_option("shrink"))
|
||||
shrink=from->get_option("shrink");
|
||||
|
||||
|
@ -70,7 +70,7 @@ private:
|
||||
static EditorTextureImportPlugin *singleton[MODE_MAX];
|
||||
//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);
|
||||
public:
|
||||
|
||||
|
@ -1156,7 +1156,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
|
||||
image_shrink = memnew( SpinBox );
|
||||
image_shrink->set_min(1);
|
||||
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);
|
||||
sections->add_child(image_vb);
|
||||
|
||||
@ -1237,7 +1237,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
|
||||
group_shrink->set_min(1);
|
||||
group_shrink->set_max(8);
|
||||
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_shrink->connect("value_changed",this,"_group_changed");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user