Fix dividing by zero crashes in texture modifiers

This commit is contained in:
cx384 2024-01-07 21:49:26 +01:00 committed by GitHub
parent 2c390b5473
commit 2766c70ad3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 27 additions and 13 deletions

View File

@ -1598,6 +1598,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
u32 frame_count = stoi(sf.next(":")); u32 frame_count = stoi(sf.next(":"));
u32 frame_index = stoi(sf.next(":")); u32 frame_index = stoi(sf.next(":"));
if (frame_count == 0){
errorstream << "generateImagePart(): invalid frame_count "
<< "for part_of_name=\"" << part_of_name
<< "\", using frame_count = 1 instead." << std::endl;
frame_count = 1;
}
if (baseimg == NULL){ if (baseimg == NULL){
errorstream<<"generateImagePart(): baseimg != NULL " errorstream<<"generateImagePart(): baseimg != NULL "
<<"for part_of_name=\""<<part_of_name <<"for part_of_name=\""<<part_of_name
@ -1659,7 +1666,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
/* /*
[multiply:color [multiply:color
or or
[screen:color [screen:color
Multiply and Screen blend modes are basic blend modes for darkening and lightening Multiply and Screen blend modes are basic blend modes for darkening and lightening
images, respectively. images, respectively.
@ -1685,7 +1692,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
if (!parseColorString(color_str, color, false)) if (!parseColorString(color_str, color, false))
return false; return false;
if (str_starts_with(part_of_name, "[multiply:")) { if (str_starts_with(part_of_name, "[multiply:")) {
apply_multiplication(baseimg, v2u32(0, 0), apply_multiplication(baseimg, v2u32(0, 0),
baseimg->getDimension(), color); baseimg->getDimension(), color);
} else { } else {
apply_screen(baseimg, v2u32(0, 0), baseimg->getDimension(), color); apply_screen(baseimg, v2u32(0, 0), baseimg->getDimension(), color);
@ -1899,6 +1906,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
u32 x0 = stoi(sf.next(",")); u32 x0 = stoi(sf.next(","));
u32 y0 = stoi(sf.next(":")); u32 y0 = stoi(sf.next(":"));
if (w0 == 0 || h0 == 0) {
errorstream << "generateImagePart(): invalid width or height "
<< "for part_of_name=\"" << part_of_name
<< "\", cancelling." << std::endl;
return false;
}
core::dimension2d<u32> img_dim = baseimg->getDimension(); core::dimension2d<u32> img_dim = baseimg->getDimension();
core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0)); core::dimension2d<u32> tile_dim(v2u32(img_dim) / v2u32(w0, h0));
@ -1965,7 +1979,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
/* /*
[hsl:hue:saturation:lightness [hsl:hue:saturation:lightness
or or
[colorizehsl:hue:saturation:lightness [colorizehsl:hue:saturation:lightness
Adjust the hue, saturation, and lightness of the base image. Like Adjust the hue, saturation, and lightness of the base image. Like
@ -1978,7 +1992,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
will be converted to a grayscale image as though seen through a will be converted to a grayscale image as though seen through a
colored glass, like "Colorize" in GIMP. colored glass, like "Colorize" in GIMP.
*/ */
else if (str_starts_with(part_of_name, "[hsl:") || else if (str_starts_with(part_of_name, "[hsl:") ||
str_starts_with(part_of_name, "[colorizehsl:")) { str_starts_with(part_of_name, "[colorizehsl:")) {
if (baseimg == nullptr) { if (baseimg == nullptr) {
@ -1995,7 +2009,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); sf.next(":");
s32 hue = mystoi(sf.next(":"), -180, 360); s32 hue = mystoi(sf.next(":"), -180, 360);
s32 saturation = sf.at_end() ? defaultSaturation : mystoi(sf.next(":"), -100, 1000); s32 saturation = sf.at_end() ? defaultSaturation : mystoi(sf.next(":"), -100, 1000);
s32 lightness = sf.at_end() ? 0 : mystoi(sf.next(":"), -100, 100); s32 lightness = sf.at_end() ? 0 : mystoi(sf.next(":"), -100, 100);
@ -2005,7 +2019,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
/* /*
[overlay:filename [overlay:filename
or or
[hardlight:filename [hardlight:filename
"A.png^[hardlight:B.png" is the same as "B.png^[overlay:A.Png" "A.png^[hardlight:B.png" is the same as "B.png^[overlay:A.Png"
@ -2069,7 +2083,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
s32 contrast = mystoi(sf.next(":"), -127, 127); s32 contrast = mystoi(sf.next(":"), -127, 127);
s32 brightness = sf.at_end() ? 0 : mystoi(sf.next(":"), -127, 127); s32 brightness = sf.at_end() ? 0 : mystoi(sf.next(":"), -127, 127);
apply_brightness_contrast(baseimg, v2u32(0, 0), apply_brightness_contrast(baseimg, v2u32(0, 0),
baseimg->getDimension(), brightness, contrast); baseimg->getDimension(), brightness, contrast);
} }
else else
@ -2347,14 +2361,14 @@ static void apply_overlay(video::IImage *blend, video::IImage *dst,
v2s32 blend_layer_pos = hardlight ? dst_pos : blend_pos; v2s32 blend_layer_pos = hardlight ? dst_pos : blend_pos;
v2s32 base_layer_pos = hardlight ? blend_pos : dst_pos; v2s32 base_layer_pos = hardlight ? blend_pos : dst_pos;
for (u32 y = 0; y < size.Y; y++) for (u32 y = 0; y < size.Y; y++)
for (u32 x = 0; x < size.X; x++) { for (u32 x = 0; x < size.X; x++) {
s32 base_x = x + base_layer_pos.X; s32 base_x = x + base_layer_pos.X;
s32 base_y = y + base_layer_pos.Y; s32 base_y = y + base_layer_pos.Y;
video::SColor blend_c = video::SColor blend_c =
blend_layer->getPixel(x + blend_layer_pos.X, y + blend_layer_pos.Y); blend_layer->getPixel(x + blend_layer_pos.X, y + blend_layer_pos.Y);
video::SColor base_c = base_layer->getPixel(base_x, base_y); video::SColor base_c = base_layer->getPixel(base_x, base_y);
double blend_r = blend_c.getRed() / 255.0; double blend_r = blend_c.getRed() / 255.0;
double blend_g = blend_c.getGreen() / 255.0; double blend_g = blend_c.getGreen() / 255.0;
double blend_b = blend_c.getBlue() / 255.0; double blend_b = blend_c.getBlue() / 255.0;
@ -2373,7 +2387,7 @@ static void apply_overlay(video::IImage *blend, video::IImage *dst,
} }
} }
/* /*
Adjust the brightness and contrast of the base image. Adjust the brightness and contrast of the base image.
Conceptually like GIMP's "Brightness-Contrast" feature but allows brightness to be Conceptually like GIMP's "Brightness-Contrast" feature but allows brightness to be
@ -2387,17 +2401,17 @@ static void apply_brightness_contrast(video::IImage *dst, v2u32 dst_pos, v2u32 s
// (we could technically allow -128/128 here as that would just result in 0 slope) // (we could technically allow -128/128 here as that would just result in 0 slope)
double norm_c = core::clamp(contrast, -127, 127) / 128.0; double norm_c = core::clamp(contrast, -127, 127) / 128.0;
double norm_b = core::clamp(brightness, -127, 127) / 127.0; double norm_b = core::clamp(brightness, -127, 127) / 127.0;
// Scale brightness so its range is -127.5 to 127.5, otherwise brightness // Scale brightness so its range is -127.5 to 127.5, otherwise brightness
// adjustments will outputs values from 0.5 to 254.5 instead of 0 to 255. // adjustments will outputs values from 0.5 to 254.5 instead of 0 to 255.
double scaled_b = brightness * 127.5 / 127; double scaled_b = brightness * 127.5 / 127;
// Calculate a contrast slope such that that no colors will get clamped due // Calculate a contrast slope such that that no colors will get clamped due
// to the brightness setting. // to the brightness setting.
// This allows the texture modifier to used as a brightness modifier without // This allows the texture modifier to used as a brightness modifier without
// the user having to calculate a contrast to avoid clipping at that brightness. // the user having to calculate a contrast to avoid clipping at that brightness.
double slope = 1 - fabs(norm_b); double slope = 1 - fabs(norm_b);
// Apply the user's contrast adjustment to the calculated slope, such that // Apply the user's contrast adjustment to the calculated slope, such that
// -127 will make it near-vertical and +127 will make it horizontal // -127 will make it near-vertical and +127 will make it horizontal
double angle = atan(slope); double angle = atan(slope);