Commit 173d329b authored by salix5's avatar salix5 Committed by GitHub

renormalize newline (#2975)

parent b824c77e
#include "image_resizer.h"
#include <cmath>
#ifdef _OPENMP
#include <omp.h>
#endif
#define STB_IMAGE_RESIZE2_IMPLEMENTATION
#include "stb_image_resize2.h"
namespace ygo {
ImageResizer imageResizer;
struct StbSamplerCache {
STBIR_RESIZE resize{};
int in_w = 0;
int in_h = 0;
int out_w = 0;
int out_h = 0;
stbir_pixel_layout layout = STBIR_BGRA;
bool samplers_built = false;
~StbSamplerCache() {
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
}
void reset_if_needed(int new_in_w, int new_in_h, int new_out_w, int new_out_h, stbir_pixel_layout new_layout) {
if(new_in_w == in_w && new_in_h == in_h && new_out_w == out_w && new_out_h == out_h && new_layout == layout)
return;
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
in_w = new_in_w;
in_h = new_in_h;
out_w = new_out_w;
out_h = new_out_h;
layout = new_layout;
resize = STBIR_RESIZE{};
}
};
/**
* Scale image using stb_image_resize2.
* Returns true on success, false on failure or unsupported format.
*/
bool ImageResizer::imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest) {
if(!src || !dest)
return false;
const auto srcDim = src->getDimension();
const auto destDim = dest->getDimension();
if(srcDim.Width == 0 || srcDim.Height == 0 || destDim.Width == 0 || destDim.Height == 0)
return false;
if(src->getColorFormat() != dest->getColorFormat())
return false;
stbir_pixel_layout layout = STBIR_BGRA;
// Fast-paths (8-bit per channel only):
// - ECF_A8R8G8B8: Irrlicht stores as BGRA in memory on little-endian.
// - ECF_R8G8B8: common for JPEGs (3 channels).
switch(src->getColorFormat()) {
case irr::video::ECF_A8R8G8B8:
layout = STBIR_BGRA;
break;
case irr::video::ECF_R8G8B8:
layout = STBIR_RGB;
break;
default:
return false;
}
void* srcPtr = src->lock();
if(!srcPtr)
return false;
void* destPtr = dest->lock();
if(!destPtr) {
src->unlock();
return false;
}
const int srcStride = (int)src->getPitch();
const int destStride = (int)dest->getPitch();
thread_local StbSamplerCache cache;
cache.reset_if_needed((int)srcDim.Width, (int)srcDim.Height, (int)destDim.Width, (int)destDim.Height, layout);
if(!cache.samplers_built) {
stbir_resize_init(&cache.resize,
srcPtr, (int)srcDim.Width, (int)srcDim.Height, srcStride,
destPtr, (int)destDim.Width, (int)destDim.Height, destStride,
layout, STBIR_TYPE_UINT8);
stbir_set_edgemodes(&cache.resize, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP);
// Use box filters to reduce aliasing when downscaling.
stbir_set_filters(&cache.resize, STBIR_FILTER_BOX, STBIR_FILTER_BOX);
cache.samplers_built = (stbir_build_samplers(&cache.resize) != 0);
if(!cache.samplers_built) {
dest->unlock();
src->unlock();
return false;
}
} else {
// Reuse samplers but update buffer pointers for the current images
stbir_set_buffer_ptrs(&cache.resize, srcPtr, srcStride, destPtr, destStride);
}
const int ok = stbir_resize_extended(&cache.resize);
dest->unlock();
src->unlock();
return ok != 0;
}
/**
* Scale image using nearest neighbor anti-aliasing.
* Function by Warr1024, from https://github.com/minetest/minetest/issues/2419, modified.
*/
void ImageResizer::imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
const auto& srcDim = src->getDimension();
const auto& destDim = dest->getDimension();
if (destDim.Width == 0 || destDim.Height == 0)
return;
// Cache scale ratios.
const double rx = (double)srcDim.Width / destDim.Width;
const double ry = (double)srcDim.Height / destDim.Height;
#pragma omp parallel if(use_threading)
{
// Walk each destination image pixel.
#pragma omp for schedule(dynamic)
for(irr::s32 dy = 0; dy < (irr::s32)destDim.Height; dy++) {
for(irr::s32 dx = 0; dx < (irr::s32)destDim.Width; dx++) {
// Calculate floating-point source rectangle bounds.
double minsx = dx * rx;
double maxsx = minsx + rx;
double minsy = dy * ry;
double maxsy = minsy + ry;
irr::u32 sx_begin = (irr::u32)std::floor(minsx);
irr::u32 sx_end = (irr::u32)std::ceil(maxsx);
if (sx_end > srcDim.Width)
sx_end = srcDim.Width;
irr::u32 sy_begin = (irr::u32)std::floor(minsy);
irr::u32 sy_end = (irr::u32)std::ceil(maxsy);
if (sy_end > srcDim.Height)
sy_end = srcDim.Height;
// Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops.
double area = 0, ra = 0, ga = 0, ba = 0, aa = 0;
irr::video::SColor pxl, npxl;
// Loop over the integral pixel positions described by those bounds.
for(irr::u32 sy = sy_begin; sy < sy_end; sy++) {
for(irr::u32 sx = sx_begin; sx < sx_end; sx++) {
// Calculate width, height, then area of dest pixel
// that's covered by this source pixel.
double pw = 1;
if(minsx > sx)
pw += sx - minsx;
if(maxsx < (sx + 1))
pw += maxsx - sx - 1;
double ph = 1;
if(minsy > sy)
ph += sy - minsy;
if(maxsy < (sy + 1))
ph += maxsy - sy - 1;
double pa = pw * ph;
// Get source pixel and add it to totals, weighted
// by covered area and alpha.
pxl = src->getPixel(sx, sy);
area += pa;
ra += pa * pxl.getRed();
ga += pa * pxl.getGreen();
ba += pa * pxl.getBlue();
aa += pa * pxl.getAlpha();
}
}
// Set the destination image pixel to the average color.
if(area > 0) {
npxl.set((irr::u32)(aa / area + 0.5),
(irr::u32)(ra / area + 0.5),
(irr::u32)(ga / area + 0.5),
(irr::u32)(ba / area + 0.5));
} else {
npxl.set(0);
}
dest->setPixel(dx, dy, npxl);
}
}
} // end of parallel region
}
void ImageResizer::resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
if(imageScaleSTB(src, dest))
return;
imageScaleNNAA(src, dest, use_threading);
}
} // namespace ygo
#include "image_resizer.h"
#include <cmath>
#ifdef _OPENMP
#include <omp.h>
#endif
#define STB_IMAGE_RESIZE2_IMPLEMENTATION
#include "stb_image_resize2.h"
namespace ygo {
ImageResizer imageResizer;
struct StbSamplerCache {
STBIR_RESIZE resize{};
int in_w = 0;
int in_h = 0;
int out_w = 0;
int out_h = 0;
stbir_pixel_layout layout = STBIR_BGRA;
bool samplers_built = false;
~StbSamplerCache() {
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
}
void reset_if_needed(int new_in_w, int new_in_h, int new_out_w, int new_out_h, stbir_pixel_layout new_layout) {
if(new_in_w == in_w && new_in_h == in_h && new_out_w == out_w && new_out_h == out_h && new_layout == layout)
return;
if(samplers_built) {
stbir_free_samplers(&resize);
samplers_built = false;
}
in_w = new_in_w;
in_h = new_in_h;
out_w = new_out_w;
out_h = new_out_h;
layout = new_layout;
resize = STBIR_RESIZE{};
}
};
/**
* Scale image using stb_image_resize2.
* Returns true on success, false on failure or unsupported format.
*/
bool ImageResizer::imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest) {
if(!src || !dest)
return false;
const auto srcDim = src->getDimension();
const auto destDim = dest->getDimension();
if(srcDim.Width == 0 || srcDim.Height == 0 || destDim.Width == 0 || destDim.Height == 0)
return false;
if(src->getColorFormat() != dest->getColorFormat())
return false;
stbir_pixel_layout layout = STBIR_BGRA;
// Fast-paths (8-bit per channel only):
// - ECF_A8R8G8B8: Irrlicht stores as BGRA in memory on little-endian.
// - ECF_R8G8B8: common for JPEGs (3 channels).
switch(src->getColorFormat()) {
case irr::video::ECF_A8R8G8B8:
layout = STBIR_BGRA;
break;
case irr::video::ECF_R8G8B8:
layout = STBIR_RGB;
break;
default:
return false;
}
void* srcPtr = src->lock();
if(!srcPtr)
return false;
void* destPtr = dest->lock();
if(!destPtr) {
src->unlock();
return false;
}
const int srcStride = (int)src->getPitch();
const int destStride = (int)dest->getPitch();
thread_local StbSamplerCache cache;
cache.reset_if_needed((int)srcDim.Width, (int)srcDim.Height, (int)destDim.Width, (int)destDim.Height, layout);
if(!cache.samplers_built) {
stbir_resize_init(&cache.resize,
srcPtr, (int)srcDim.Width, (int)srcDim.Height, srcStride,
destPtr, (int)destDim.Width, (int)destDim.Height, destStride,
layout, STBIR_TYPE_UINT8);
stbir_set_edgemodes(&cache.resize, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP);
// Use box filters to reduce aliasing when downscaling.
stbir_set_filters(&cache.resize, STBIR_FILTER_BOX, STBIR_FILTER_BOX);
cache.samplers_built = (stbir_build_samplers(&cache.resize) != 0);
if(!cache.samplers_built) {
dest->unlock();
src->unlock();
return false;
}
} else {
// Reuse samplers but update buffer pointers for the current images
stbir_set_buffer_ptrs(&cache.resize, srcPtr, srcStride, destPtr, destStride);
}
const int ok = stbir_resize_extended(&cache.resize);
dest->unlock();
src->unlock();
return ok != 0;
}
/**
* Scale image using nearest neighbor anti-aliasing.
* Function by Warr1024, from https://github.com/minetest/minetest/issues/2419, modified.
*/
void ImageResizer::imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
const auto& srcDim = src->getDimension();
const auto& destDim = dest->getDimension();
if (destDim.Width == 0 || destDim.Height == 0)
return;
// Cache scale ratios.
const double rx = (double)srcDim.Width / destDim.Width;
const double ry = (double)srcDim.Height / destDim.Height;
#pragma omp parallel if(use_threading)
{
// Walk each destination image pixel.
#pragma omp for schedule(dynamic)
for(irr::s32 dy = 0; dy < (irr::s32)destDim.Height; dy++) {
for(irr::s32 dx = 0; dx < (irr::s32)destDim.Width; dx++) {
// Calculate floating-point source rectangle bounds.
double minsx = dx * rx;
double maxsx = minsx + rx;
double minsy = dy * ry;
double maxsy = minsy + ry;
irr::u32 sx_begin = (irr::u32)std::floor(minsx);
irr::u32 sx_end = (irr::u32)std::ceil(maxsx);
if (sx_end > srcDim.Width)
sx_end = srcDim.Width;
irr::u32 sy_begin = (irr::u32)std::floor(minsy);
irr::u32 sy_end = (irr::u32)std::ceil(maxsy);
if (sy_end > srcDim.Height)
sy_end = srcDim.Height;
// Total area, and integral of r, g, b values over that area,
// initialized to zero, to be summed up in next loops.
double area = 0, ra = 0, ga = 0, ba = 0, aa = 0;
irr::video::SColor pxl, npxl;
// Loop over the integral pixel positions described by those bounds.
for(irr::u32 sy = sy_begin; sy < sy_end; sy++) {
for(irr::u32 sx = sx_begin; sx < sx_end; sx++) {
// Calculate width, height, then area of dest pixel
// that's covered by this source pixel.
double pw = 1;
if(minsx > sx)
pw += sx - minsx;
if(maxsx < (sx + 1))
pw += maxsx - sx - 1;
double ph = 1;
if(minsy > sy)
ph += sy - minsy;
if(maxsy < (sy + 1))
ph += maxsy - sy - 1;
double pa = pw * ph;
// Get source pixel and add it to totals, weighted
// by covered area and alpha.
pxl = src->getPixel(sx, sy);
area += pa;
ra += pa * pxl.getRed();
ga += pa * pxl.getGreen();
ba += pa * pxl.getBlue();
aa += pa * pxl.getAlpha();
}
}
// Set the destination image pixel to the average color.
if(area > 0) {
npxl.set((irr::u32)(aa / area + 0.5),
(irr::u32)(ra / area + 0.5),
(irr::u32)(ga / area + 0.5),
(irr::u32)(ba / area + 0.5));
} else {
npxl.set(0);
}
dest->setPixel(dx, dy, npxl);
}
}
} // end of parallel region
}
void ImageResizer::resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading) {
if(imageScaleSTB(src, dest))
return;
imageScaleNNAA(src, dest, use_threading);
}
} // namespace ygo
#ifndef IMAGE_RESIZER_H
#define IMAGE_RESIZER_H
#include <irrlicht.h>
namespace ygo {
class ImageResizer {
private:
bool imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest);
void imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
public:
void resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
};
extern ImageResizer imageResizer;
} // namespace ygo
#endif // IMAGE_RESIZER_H
#ifndef IMAGE_RESIZER_H
#define IMAGE_RESIZER_H
#include <irrlicht.h>
namespace ygo {
class ImageResizer {
private:
bool imageScaleSTB(irr::video::IImage* src, irr::video::IImage* dest);
void imageScaleNNAA(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
public:
void resize(irr::video::IImage* src, irr::video::IImage* dest, bool use_threading);
};
extern ImageResizer imageResizer;
} // namespace ygo
#endif // IMAGE_RESIZER_H
/****************************************************************************
*
* ft2build.h
*
* FreeType 2 build and setup macros.
*
* Use custom/ft2build.h instead of the default include/freetype/ft2build.h
* to customize the FreeType 2 build of YGOPro.
*
*/
#ifndef FT2_BUILD_MY_PLATFORM_H_
#define FT2_BUILD_MY_PLATFORM_H_
#define FT_CONFIG_OPTIONS_H <ygopro/ftoption.h>
#define FT_CONFIG_MODULES_H <ygopro/ftmodule.h>
#include <freetype/config/ftheader.h>
#endif /* FT2_BUILD_MY_PLATFORM_H_ */
/****************************************************************************
*
* ft2build.h
*
* FreeType 2 build and setup macros.
*
* Use custom/ft2build.h instead of the default include/freetype/ft2build.h
* to customize the FreeType 2 build of YGOPro.
*
*/
#ifndef FT2_BUILD_MY_PLATFORM_H_
#define FT2_BUILD_MY_PLATFORM_H_
#define FT_CONFIG_OPTIONS_H <ygopro/ftoption.h>
#define FT_CONFIG_MODULES_H <ygopro/ftmodule.h>
#include <freetype/config/ftheader.h>
#endif /* FT2_BUILD_MY_PLATFORM_H_ */
/*
* This file registers the FreeType modules compiled into the library.
*
* YGOPro only uses modules that are needed for TrueType and OpenType fonts.
*
*/
FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class )
FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class )
FT_USE_MODULE( FT_Module_Class, psaux_module_class )
FT_USE_MODULE( FT_Module_Class, psnames_module_class )
FT_USE_MODULE( FT_Module_Class, pshinter_module_class )
FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
/* EOF */
/*
* This file registers the FreeType modules compiled into the library.
*
* YGOPro only uses modules that are needed for TrueType and OpenType fonts.
*
*/
FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class )
FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class )
FT_USE_MODULE( FT_Module_Class, psaux_module_class )
FT_USE_MODULE( FT_Module_Class, psnames_module_class )
FT_USE_MODULE( FT_Module_Class, pshinter_module_class )
FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
/* EOF */
/****************************************************************************
*
* ftoption.h
*
* User-selectable configuration macros (specification only).
*
* This file is customized for YGOPro to include only the necessary
* configuration options for the TrueType and OpenType font driver.
*
* See the original FreeType source code for more information.
* /include/freetype/config/ftoption.h
*
*/
#ifndef FTOPTION_H_
#define FTOPTION_H_
#include <ft2build.h>
FT_BEGIN_HEADER
#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
#undef FT_CONFIG_OPTION_FORCE_INT64
#define FT_CONFIG_OPTION_INLINE_MULFIX
#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES
#define FT_CONFIG_OPTION_INCREMENTAL
#define FT_RENDER_POOL_SIZE 16384L
#define FT_MAX_MODULES 32
#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS
#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
#define TT_CONFIG_OPTION_COLOR_LAYERS
#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES
#define TT_CONFIG_CMAP_FORMAT_0
#define TT_CONFIG_CMAP_FORMAT_2
#define TT_CONFIG_CMAP_FORMAT_4
#define TT_CONFIG_CMAP_FORMAT_6
#define TT_CONFIG_CMAP_FORMAT_8
#define TT_CONFIG_CMAP_FORMAT_10
#define TT_CONFIG_CMAP_FORMAT_12
#define TT_CONFIG_CMAP_FORMAT_13
#define TT_CONFIG_CMAP_FORMAT_14
#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES
#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L
#endif
#define T1_MAX_SUBRS_CALLS 16
#define T1_MAX_CHARSTRINGS_OPERANDS 256
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#define TT_USE_BYTECODE_INTERPRETER
#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
#endif
#endif
#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
#define TT_SUPPORT_COLRV1
#endif
FT_END_HEADER
#endif /* FTOPTION_H_ */
/* END */
/****************************************************************************
*
* ftoption.h
*
* User-selectable configuration macros (specification only).
*
* This file is customized for YGOPro to include only the necessary
* configuration options for the TrueType and OpenType font driver.
*
* See the original FreeType source code for more information.
* /include/freetype/config/ftoption.h
*
*/
#ifndef FTOPTION_H_
#define FTOPTION_H_
#include <ft2build.h>
FT_BEGIN_HEADER
#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
#undef FT_CONFIG_OPTION_FORCE_INT64
#define FT_CONFIG_OPTION_INLINE_MULFIX
#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES
#define FT_CONFIG_OPTION_INCREMENTAL
#define FT_RENDER_POOL_SIZE 16384L
#define FT_MAX_MODULES 32
#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS
#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
#define TT_CONFIG_OPTION_COLOR_LAYERS
#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES
#define TT_CONFIG_CMAP_FORMAT_0
#define TT_CONFIG_CMAP_FORMAT_2
#define TT_CONFIG_CMAP_FORMAT_4
#define TT_CONFIG_CMAP_FORMAT_6
#define TT_CONFIG_CMAP_FORMAT_8
#define TT_CONFIG_CMAP_FORMAT_10
#define TT_CONFIG_CMAP_FORMAT_12
#define TT_CONFIG_CMAP_FORMAT_13
#define TT_CONFIG_CMAP_FORMAT_14
#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES
#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L
#endif
#define T1_MAX_SUBRS_CALLS 16
#define T1_MAX_CHARSTRINGS_OPERANDS 256
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333
#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#define TT_USE_BYTECODE_INTERPRETER
#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
#endif
#endif
#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
#define TT_SUPPORT_COLRV1
#endif
FT_END_HEADER
#endif /* FTOPTION_H_ */
/* END */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment