Image.getPixel/setPixel & ImagePainter – editing JME3 Images

THIS VERSION OF IMAGEPAINTER IS NOW OBSOLETE, SEE THIS THREAD FOR THE NEW PLUGIN-BASED VERSION:

http://hub.jmonkeyengine.org/groups/user-code-projects/forum/topic/image-painter-plugin-available/



Hi all,



As discussed here http://hub.jmonkeyengine.org/groups/graphics/forum/topic/adding-getpixel-in-image/ I’ve been adding some new functionality to JME3 Images.



I’ve converted my own game to use the new functions and done a load of testing on them now so they should be in a pretty “final” state and ready to use.



The complete Image.java file is at http://www.zero-separation.com/temp/Image.java

Or a patch version is at http://www.zero-separation.com/temp/Image.java.diff



The new Java file for ImagePainter is at http://www.zero-separation.com/temp/ImagePainter.java

It should be placed in the same package as Image.java



The new Java file for the test is at http://www.zero-separation.com/temp/ImageAndImagePainter.java

It should be added to the JME3 Tests project in the jme3test.texture package.







I even did a video introduction to it:

http://www.youtube.com/watch?v=l_1PvEeHw98


If you want to see the results and skip the intro waffle about the code then jump to 6:57.












@Sploreg said:
Yea we talked about this in the chat when the issue came up. Moving get/setPixel() to image is the ideal solution, then android can hide its hacks behind the scenes.
I'm heading on vacation for a few weeks starting tomorrow, so someone else might have to take the reins on it: @normen, @Momoko_Fan, of course if you want to implement it that would be *wonderful!* We can guide you and help work out an ideal solution for all situations.


I'm looking at you guys to get this integrated into core :p
13 Likes

so sweet :slight_smile: <3

1 Like

Next time I need to get my girlfriend to turn off her music. I did a test and couldn’t hear it at all, did the full thing and uploaded to youtube and suddenly it was very audible.

I really hope this is added to the core (eventually). Got 3 things ready to be replaced right away.

1 Like

This is really impressive stuff. Thanks for sharing!

1 Like

I think we just got ourselves a new golden standard for code contributions :stuck_out_tongue:

1 Like

I recently started doing some image operations like converting from any image to a 16 bit greyscale image to use as seed for density maps (and height maps). With this I can skip all BufferedImage and all that java2D-stuff and just get things done. Thanks for sharing! I hope it will end up in core.

1 Like
@wezrule said:
so sweet ^_^ <3


:)

@androlo said:
I really hope this is added to the core (eventually). Got 3 things ready to be replaced right away.


Me too.

@kwando said:
This is really impressive stuff. Thanks for sharing!


Thanks.

@erlend_sh said:
I think we just got ourselves a new golden standard for code contributions :P


I liked that comment so much I mentioned it in the first tweet from my new twitter account :)
(I also added jmonkeyengine as my one and only person I'm following)

@jmaasing said:
I recently started doing some image operations like converting from any image to a 16 bit greyscale image to use as seed for density maps (and height maps). With this I can skip all BufferedImage and all that java2D-stuff and just get things done. Thanks for sharing! I hope it will end up in core.


That's the idea. Especially since Java2D isn't supported on Android.
1 Like

Looks great, could come in handy in the future, thanks!

i know it’s fresh topic, but will it be added to core soon? (i use nightly and seen no changes)



because i don’t know, if i need to wait, or replace it myself.



BTW; all thanks to zarch.

Any news on this?

It is in development, please wait …

Hey Zarch,



Is there a way to use this code between now and when it merges into the core? If so, is there an updated source link? (the links above are 404).



Thanks, and nice work.

I’ve updated the links above (tmp had changed to temp on our web server for some reason), however this project has hit a bit of a hitch at the moment. A different implementation of get/set pixel went into core (see ImageRaster) and so I need to change ImagePainter to use it. It’s not a big job but considering what we have is working perfectly and there were some performance issues with the first implementations of ImageRaster I’ve just not found the time to do it.

This is amazing! I did something similar on a much much smaller scale, I may throw out that work now, this is a significant upgrade! I would love to see this merged into the engine.

Well @momoko_fan doesn’t agree so not much I can do about that.



I’ll try and find time this week to port ImagePainter over to ImageRaster and then it can be available as a contribution plugin although I’m still not happy about the performance loss.

Hi Zarch,



Could you post a link to the jME Application code you ran to demonstrate your image classes? The code of the app that you ran in the video, that is. We could use your code as a kind of “tutorial” of how to implement these classes. Thanks.



Alf

It’s linked in the first post, it’s the file for the test.



Be aware it’s not particularly well commented or organised, just thrown together. You are probably better looking at the javadoc for ImagePainter.

Thanks for the link updates Zarch. The change to use ImageRaster was straightforward, as you expected. I didn’t do a diff because it’d make this post too long, and they’re relatively simple. The basic changes though, were: (hopefully I didn’t mangle anything obvious :wink: )



[java]

private final Image image;

private final ImageRaster imageRaster;

private final ColorRGBA working = new ColorRGBA();

[/java]

[java]

public ImagePainter(Image image) {

this.image = image;

imageRaster = ImageRaster.create( image );

}



public ImagePainter(Format format, int width, int height) {

ByteBuffer buffer = ByteBuffer.allocateDirect(widthheightformat.getBitsPerPixel()/8);

this.image = new Image(format, width, height, buffer);

imageRaster = ImageRaster.create( image );

}

[/java]

ImageRaster member and constructor updates





[java]

image.width;

// vs

image.getWidth();

[/java]

Width/height access swapped with Image class get/set





[java]

public void paintPixel(int x, int y, ColorRGBA color, BlendMode mode) {

imageRaster.getPixel(x, y, paintWorking);

mode.apply(paintWorking, color.r, color.g, color.b, color.a);

imageRaster.setPixel(x, y, paintWorking);

}

[/java]

paintPixel change







One question I had though - do you know how heavy (performance-wise) creating an ImageRaster is? As in, within methods like paintImage (and the other paint*Image methods), I created an imageRaster for the source, then used it:

[java]

public void paintImage(int startX, int startY, Image source, BlendMode mode, float opacity) {



// … snipped …



// Draw pixels

ImageRaster sourceRaster = ImageRaster.create( source );

for (int y=startY+rowOffset;y<yLimit;y++) {

for (int x=startX+lineOffset;x<xLimit;x++) {

sourceRaster.getPixel(x-startX, y-startY, working);

working.a *= opacity;

paintPixel(x, y, working, mode);

}



}

}

[/java]



I don’t have an advanced enough bit of test code to test performance yet, but just curious.



ImagePainter is pretty cool, going to have fun tinkering around with it. Thanks again. :smiley:

2 Likes

It’s not very heavyweight I think (not much data stored, just code) so shouldn’t be a big problem. That is one of the things I wanted to think about when I made the change though.



I was thinking that maybe ImagePainter should inherit (rather than encapsulate) from ImageRaster and all the parameters that currently take an Image should take an ImageRaster instead.



Then you could pass ImagePainters or ImageRasters to each other and you could re-use ImageRasters that you were using a lot rather than recreating them all the time.