duncathan said:In case you don't see noxid's point, he means that it's (theoretically?) already cross-compatible.
Well my fucking bad then, I guess. Sorry for providing helpful information in case you needed it.Thunderchin said:I do see his point. I'm not the complete idiot you seem to think I am.
You're one to talk.Noxid said:ah, hayden, why you go n' do that for
Fair enough.Noxid said:well the key difference is I provided it as an option, not the sole source of the program
I increased the stack size. With the default stack size, the NICALiS graphics filtering process will freeze if you give it an image with large enough clumps of pixels that match sections from NICALiS sprite sheets.Noxid said:what JVM option are you tweaking
I think you'll need to explain how you're doing this, or maybe pastebin some code, because I have no idea how you're using the entire stack with this process (this smells like bad code).HaydenStudios said:I increased the stack size. With the default stack size, the NICALiS graphics filtering process will freeze if you give it an image with large enough clumps of pixels that match sections from NICALiS sprite sheets.
That's what I was thinking, I just haven't found out what the precise commandline syntax for that is yet. I probably won't have to do much digging, though.Noxid said:yeah, what dunc said would work
The coordinates won't always be the same on each end, though. And we're not just scanning for character sprites, but also patterns from 2x res backgrounds, face pictures, and credit images as well. Those generally aren't neatly divided into discernible sections.Noxid said:And, I reckon there's probably more efficient ways of doing that. Like, breaking the image up into 16x16 / 32x32 chunks and comparing them sequentially, since the coords have to be the same on each end anyway and all the sprites are multiples of 8 or 16 at least
When an image is loaded for filtering, it first is scanned for any clumps of pixels that are too small to be considered worthwhile matches. It then loads the first file on the list of 2x res images to compare it to. Before it begins scanning for matching patterns, it first goes through some filters. The first filter analyzes all the colors present in the 2 images. If the number of colors they share is any less than 2, then the image is skipped, and the image being filtered is then compared with the next file on the list of images in the CS+ directory. If they have enough colors in common, the process will continue. The program then sees if there are any colors that the two images don't have in common, and if so then it makes sure that the locations of those colors in the images will be ignored. It then begins the main scanning phase which takes place as follows:GIRakaCHEEZER said:I think you'll need to explain how you're doing this, or maybe pastebin some code, because I have no idea how you're using the entire stack with this process (this smells like bad code).
Start at the first pixel of image 1:
{
If for some reason this pixel is one we've been told to ignore:
Move onto the next pixel in image 1
Start at the first pixel of image 2:
{
If for some reason this pixel is one we've been told to ignore:
Move onto the next pixel in image 2
If said pixel in image 1 is the same color as said pixel in image 2:
{
See if the corresponding pixels of the images match in the 8 surrounding pixels
If so, then see if it matches the 8 pixels around that as well, and keep going until you reach a dead end
If the pattern has enough pixels/colors, then the clump is declared as filtered; it will then ignore all pixels involved
}
If said pixel in image 1 is NOT the same color as said pixel in image 2:
Move on to the next pixel in image 2
}
When you've reached the last pixel of image 2, move onto the next pixel of image 1, and start back at the first pixel of image 2
}
When you've reached the last pixel of image 1, the scanning process is complete. It now loads a new image to compare image 1 to.
Set the image getting replaced as image 2
Start at the first pixel:
{
If said pixel from image 1 matches said pixel from image 2, set said pixel as a filtered point that will be ignored when scanning
If said pixel from image 1 does NOT match said pixel from image 2, then do nothing
Move onto the next pixel
}
That's right.Noxid said:Ok so, these port packs need to be installed by your program to recombine the graphics with existing assets, I assume?
If said mod has filtered images, then that's right; some of the graphics will look like they just came out of a shredder if you try to do that. If the port doesn't have any filtered images, though, then just dropping the folder in there and modifying mods.txt will work fine.Noxid said:Like, you can't just drop them into the mods folder and take off running.
public static void main(String... args) throws IOException {
File canon = new File("faceCanon.bmp"), modded = new File("face1.bmp"), filtered = new File("filtered.png");
File result = new File("final.bmp");
filter(canon,modded,filtered);
applyFilter(canon, filtered, result);
}
public static void filter(File canonfile, File moddedFile, File output) throws IOException {
BufferedImage canon = ImageIO.read(canonfile);
BufferedImage modded = ImageIO.read(moddedFile);
BufferedImage out = new BufferedImage(modded.getWidth(), modded.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < modded.getHeight(); y++) {
for (int x = 0; x < modded.getWidth(); x++) {
if ((x >= canon.getWidth() && y >= canon.getHeight())
|| canon.getRGB(x, y) != modded.getRGB(x, y)) {
out.setRGB(x, y, modded.getRGB(x, y));
}
}
}
ImageIO.write(out, "png", output);
}
public static void applyFilter(File canonFile, File filterFile, File output) throws IOException {
BufferedImage canon = ImageIO.read(canonFile);
BufferedImage filter = ImageIO.read(filterFile);
BufferedImage out = new BufferedImage(filter.getWidth(), filter.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = out.getGraphics();
g.drawImage(canon, 0, 0, null);
g.drawImage(filter, 0, 0, null);
g.dispose();
ImageIO.write(out, "bmp", output);
}
All right. I hesitated to paste it at first because there's a bunch of extra stuff in it that takes some other things into account, but here's a condensed version of the algorithm:Can I actually see the code instead of your pseudo-code representation of this comparison function, since this really some terrible pseudo-code/I can't follow this well at all.
for(int y1 = 0; y1 < image1.getHeight(); y1++)
for(int x1 = 0; x1 < image1.getWidth(); x1++)
if(!tempBlankPixels1[y1][x1] && !linkedPixels[y1][x1])
for(int y2 = 0; y2 < image2.getHeight(); y2++)
for(int x2 = 0; x2 < image2.getWidth(); x2++)
if(!blankPixels2[y2][x2] && skipLinked)
if(new Color(image1.getRGB(x1, y1)).equals(new Color(image2.getRGB(x2, y2))))
TestMatch(image1, image2, x1, y1, x2, y2, true);
private static void TestMatch(BufferedImage image1, BufferedImage image2, int x1, int y1, int x2, int y2, boolean source)
{
if( ( ((x1 >= 0 && y1 >= 0) && (x2 >= 0 && y2 >= 0)) && (x1 <= image1.getWidth()-1 && x2 <= image2.getWidth()-1)) && ((y1 <= image1.getHeight()-1) && (y2 <= image2.getHeight()-1)) )
{
TestMatch(image1, image2, x1 + 1, y1, x2 + 1, y2, false);
TestMatch(image1, image2, x1 + 1, y1 + 1, x2 + 1, y2 + 1, false);
TestMatch(image1, image2, x1, y1 + 1, x2, y2 + 1, false);
TestMatch(image1, image2, x1 - 1, y1 + 1, x2 - 1, y2 + 1, false);
TestMatch(image1, image2, x1 - 1, y1, x2 - 1, y2, false);
TestMatch(image1, image2, x1 - 1, y1 - 1, x2 - 1, y2 - 1, false);
TestMatch(image1, image2, x1, y1 - 1, x2, y2 - 1, false);
TestMatch(image1, image2, x1 + 1, y1 - 1, x2 + 1, y2 - 1, false);
}
}
Easily. In the example, just pretend that we're using the 2x res images. This here is the modified PrtSand tileset image for my fourth ending mod:ok, well, I think you're overthinking your problem. Can you give me a counter-case to this algorithm:Code:public static void main(String... args) throws IOException { File canon = new File("faceCanon.bmp"), modded = new File("face1.bmp"), filtered = new File("filtered.png"); File result = new File("final.bmp"); filter(canon,modded,filtered); applyFilter(canon, filtered, result); } public static void filter(File canonfile, File moddedFile, File output) throws IOException { BufferedImage canon = ImageIO.read(canonfile); BufferedImage modded = ImageIO.read(moddedFile); BufferedImage out = new BufferedImage(modded.getWidth(), modded.getHeight(), BufferedImage.TYPE_INT_ARGB); for (int y = 0; y < modded.getHeight(); y++) { for (int x = 0; x < modded.getWidth(); x++) { if ((x >= canon.getWidth() && y >= canon.getHeight()) || canon.getRGB(x, y) != modded.getRGB(x, y)) { out.setRGB(x, y, modded.getRGB(x, y)); } } } ImageIO.write(out, "png", output); } public static void applyFilter(File canonFile, File filterFile, File output) throws IOException { BufferedImage canon = ImageIO.read(canonFile); BufferedImage filter = ImageIO.read(filterFile); BufferedImage out = new BufferedImage(filter.getWidth(), filter.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics g = out.getGraphics(); g.drawImage(canon, 0, 0, null); g.drawImage(filter, 0, 0, null); g.dispose(); ImageIO.write(out, "bmp", output); }