Skip to content

Commit

Permalink
Nearest Neighbor Color Removal (#2281)
Browse files Browse the repository at this point in the history
* Use nearest neighbor to set alpha of removed color from images like GM8.1
* Give each sprite frame its own bottom-left transparency pixel like GM8.1
* Use removed color instead of black in transparent areas like GM8.1
* Ensure isolated pixels are always visible like GM8.1
  • Loading branch information
RobertBColton committed Nov 11, 2021
1 parent 91a1b3b commit df4c018
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 22 deletions.
5 changes: 1 addition & 4 deletions ENIGMAsystem/SHELL/Graphics_Systems/General/GSscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ RawImage create_from_screen_helper(int x, int y, int w, int h, bool removeback,
if (flipped)
enigma::image_flip(i);

if (removeback) {
Color c = enigma::image_get_pixel_color(i, 0, h - 1);
enigma::image_swap_color(i, c, Color {0, 0, 0, 0});
}
if (removeback) enigma::image_remove_color(i);

return i;
}
Expand Down
5 changes: 1 addition & 4 deletions ENIGMAsystem/SHELL/Graphics_Systems/General/GSsurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,7 @@ int background_create_from_surface(int id, int x, int y, int w, int h, bool remo

enigma::RawImage s(enigma::graphics_copy_texture_pixels(base.texture,x,y,w,h), w, h);

if (removeback) {
enigma::Color c = enigma::image_get_pixel_color(s, 0, h - 1);
enigma::image_swap_color(s, c, enigma::Color {0, 0, 0, 0});
}
if (removeback) enigma::image_remove_color(s);

unsigned fullwidth, fullheight;
int texID = enigma::graphics_create_texture(s, false, &fullwidth, &fullheight);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@ Background background_add_helper(std::string filename, bool transparent, bool sm

// If background is transparent, set the alpha to zero for pixels that should be
// transparent from lower left pixel color
if (transparent) {
Color c = enigma::image_get_pixel_color(imgs[0], 0, imgs[0].h - 1);
enigma::image_swap_color(imgs[0], c, Color {0, 0, 0, 0});
}
if (transparent) enigma::image_remove_color(imgs[0]);

nb.textureID = graphics_create_texture(imgs[0], mipmap, &fullwidth, &fullheight);
nb.textureBounds = TexRect(0, 0, static_cast<gs_scalar>(imgs[0].w) / fullwidth, static_cast<gs_scalar>(imgs[0].h) / fullheight);
Expand Down
12 changes: 2 additions & 10 deletions ENIGMAsystem/SHELL/Universal_System/Resources/sprites.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,17 @@ Sprite sprite_add_helper(std::string filename, int imgnumb, bool precise, bool t
unsigned cellwidth = ((imgs.size() > 1) ? imgs[0].w : imgs[0].w / imgnumb);
Sprite ns(cellwidth, imgs[0].h, x_offset, y_offset);
ns.SetBBox(0, 0, cellwidth, imgs[0].h);

// If sprite transparent, set the alpha to zero for pixels that should be
// transparent from lower left pixel color
Color c = enigma::image_get_pixel_color(imgs[0], 0, imgs[0].h - 1);

if (imgs.size() == 1 && imgnumb > 1) {
if (transparent) {
enigma::image_swap_color(imgs[0], c, Color {0, 0, 0, 0});
}
if (transparent) enigma::image_remove_color(imgs[0]);

std::vector<RawImage> rawSubimages = enigma::image_split(imgs[0], imgnumb);
for (const RawImage& i : rawSubimages) {
ns.AddSubimage(i, ((precise) ? enigma::ct_precise : enigma::ct_bbox), i.pxdata, mipmap);
}
} else {
for (RawImage& i : imgs) {
if (transparent) {
enigma::image_swap_color(i, c, Color {0, 0, 0, 0});
}
if (transparent) enigma::image_remove_color(i);
ns.AddSubimage(i, ((precise) ? enigma::ct_precise : enigma::ct_bbox), i.pxdata, mipmap);
}
}
Expand Down
50 changes: 50 additions & 0 deletions ENIGMAsystem/SHELL/Universal_System/image_formats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,56 @@ void image_swap_color(RawImage& in, Color oldColor, Color newColor) {
}
}

void image_remove_color(RawImage& in, Color oldColor) {
#ifdef DEBUG_MODE
if (in.pxdata == nullptr) {
in.pxdata = new unsigned char[in.w * in.h * 4];
std::fill(in.pxdata, in.pxdata + (in.w * in.h * 4), 255);
DEBUG_MESSAGE("Attempt to access a null pointer" , MESSAGE_TYPE::M_ERROR);
return;
}
#endif

unsigned int ih, iw;
for (ih = 0; ih < in.h; ih++) {
int index = ih * in.w * 4;

for (iw = 0; iw < in.w; iw++) {
if (
in.pxdata[index] == oldColor.b
&& in.pxdata[index + 1] == oldColor.g
&& in.pxdata[index + 2] == oldColor.r
) {
in.pxdata[index + 3] = 0;
} else {
unsigned int nw = (iw <= 0 ? iw : iw - 1),
nh = (ih <= 0 ? ih : ih - 1);
float neighbors = 0, counted = 0;
for (; nh <= ih + 1 && nh < in.h; ++nh) {
for (; nw <= iw + 1 && nw < in.w; ++nw) {
++counted;
int ni = (nh * in.w + nw) * 4;
if (
in.pxdata[ni] != oldColor.b
|| in.pxdata[ni + 1] != oldColor.g
|| in.pxdata[ni + 2] != oldColor.r
)
++neighbors;
}
}
in.pxdata[index + 3] = static_cast<unsigned char>((neighbors/counted) * 255.0f);
}

index += 4;
}
}
}

void image_remove_color(RawImage& in) {
Color bottom_left = image_get_pixel_color(in, 0, in.h - 1);
image_remove_color(in, bottom_left);
}

std::vector<RawImage> image_split(const RawImage& in, unsigned imgcount) {
std::vector<RawImage> imgs(imgcount);
unsigned splitWidth = in.w / imgcount;
Expand Down
2 changes: 2 additions & 0 deletions ENIGMAsystem/SHELL/Universal_System/image_formats.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ enum {

Color image_get_pixel_color(const RawImage& in, unsigned x, unsigned y);
void image_swap_color(RawImage& in, Color oldColor, Color newColor);
void image_remove_color(RawImage& in, Color oldColor);
void image_remove_color(RawImage& in);
/// Note splits horizontally
std::vector<RawImage> image_split(const RawImage& in, unsigned imgcount);
RawImage image_pad(const RawImage& in, unsigned newWidth, unsigned newHeight);
Expand Down

0 comments on commit df4c018

Please sign in to comment.