Still having problems with texture generation

I’m still having big problems with the texture generation but I’ve discovered more about it. It seems like no matter what I try to do, the DefaultImageRaster fails to reset after I load new textures. I took everyone’s advice and added logging, and for 3 weeks I didn’t find a single thing to help me on the subject of it, nor did I find anything in my code or what was outputted that would hint at anything wrong. I’ve even made a class (just for testing) that extended Node and I made it so calling “setMaterial()” did nothing but output a line saying “setMaterial called for spatial (spatial’s name)!” and then some details about the material that was in the method. This method was never called. I had the actual model of the spatial I was trying to texture in a node, which was a child to the class that extends node. The ONLY way to set this model’s material was to call “buildMaterial()”, which would output the model, the material, the material’s diffuse texture, and pretty much anything else you can think of that could be derived from the data given. Never once was this method called either. The textures were still changed on models which didn’t output anything. I detach everything from it’s parent nodes, apply materials to changed models, then re-attach. I see no possible way for the textures to be applied to any of the other models. I’ve seriously tried everything I possibly can, and the last thing I can think of that could be the problem is the ImageRaster class or the DefaultImageRaster. I tried to use the ImagePainter plug-in and it was just too much. I couldn’t figure out how to even iterate over the pixels.

That’s about it, I’m still lost so if anyone has any idea, please tell me. Thanks in advance.

First you say " the DefaultImageRaster fails to reset after I load new textures"…

…then you go on to describe how textures end up on models that they aren’t supposed to be on.

At this point, I’m not really sure which it is based on your monster paragraph. I tried to follow it but it was kind of a “maze of twisty passages” with no code for guidance.

If you want help, you should explain how you create the raster, how you create the texture, Image, etc. and how it gets applied to the geometry. Preferably with some code.

As it is, my only guess is that you keep using the same DefaultImageRaster and so then all of your geometries end up getting the same changes in texture.

It sounds like you are pretty confused on something. Try clearly and concisely explaining

  1. What you are trying to have happen.
  2. What actually happens.
  3. What you are doing to make this happen.

Alright, sorry. I was in a hurry to type that last post.

@pspeed I’m not using the same DefaultImageRaster each time, and even if I was I manually clear it to black each time. Here’s the method for generating the textures:

[java]
public Material build() {
if (!isBuilt) {
isBuilt = true;
Texture tempTex = AssetLoading.getAssetManager().loadTexture(“Textures/Weapons/Template.png”).clone();
Image output = tempTex.getImage().clone();
DefaultImageRaster outputPainter = new DefaultImageRaster(output, 0);
int nonBlack = 0;
for (int x = 0; x < 800; x++) {
for (int y = 0; y < 800; y++) {
if (outputPainter.getPixel(x, y).getRed() != 0.0 && outputPainter.getPixel(x, y).getGreen() != 0.0 && outputPainter.getPixel(x, y).getBlue() != 0.0) {
nonBlack++;
}
outputPainter.setPixel(x, y, ColorRGBA.Black);
}
}
System.out.println("— " + name + "\nNon-black pixels: " + nonBlack);
canSetMain = true;
canSetSec = true;
canSetExtra = true;
setMainColor(outputPainter);
setSecondaryColor(outputPainter);
setExtraColor(outputPainter);
Texture2D finalTex = new Texture2D(output.clone());
finalTex.setName(name + “_texture”);
finalMaterial = new Material(AssetLoading.getAssetManager(), “Common/MatDefs/Light/Lighting.j3md”);
finalMaterial.setTexture(“DiffuseMap”, finalTex.clone());
finalMaterial.setName(name);
return finalMaterial;
} else {
return null;
}
}
[/java]

As you can see, I load the template texture, clone it, take it's image, clone it, paint it, then clone it again. Each of the setColor methods looks something like the following:

[java]
private void setMainColor(DefaultImageRaster outputPainter) {
if (canSetMain) {
canSetMain = false;
Texture tex = AssetLoading.getAssetManager().loadTexture("Textures/Weapons/" + weaponType.toString() + "/" + name + "_main.png");
Image main = tex.getImage();
DefaultImageRaster tintingMachineMain = new DefaultImageRaster(main, 0);
for (int x = 1; x < 800; x++) {
for (int y = 1; y < 800; y++) {
try {
ColorRGBA curPixel = tintingMachineMain.getPixel(x, y);
if (curPixel.getRed() == 1 && curPixel.getGreen() == 1 && curPixel.getBlue() == 1) {
outputPainter.setPixel(x, 800 - y, mainColor);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
[/java]

I'm using x, 800-y as the position to flip the image by the way.

@zarch

What should be happening is the colors should be painted to the output image, which is applied to a texture and given to a material for the weapon part.

Here is an image of what really happens:

The lower handle part has the texture of the top slide part. The output is exactly as it should be, showing that the handle’s material was changed to a material with the name “Base2,” texture named “Base2_texture,” and the correct colors.

I don’t do anything special to make this happen, nor is there any rhyme or reason to when it happens. It seems to be entirely random. I output a lot of things while running this and I’m still pretty lost. All of the outputs seem correct except for the number of non-black pixels each time I customize another color.

Here’s the aforementioned buildMaterial() method:

[java]
public void buildMaterial(ColorRGBA main, ColorRGBA sec, ColorRGBA extra) {
Material mat = new WeaponMaterial(getName(), type).setColors(main, sec, extra).build();
//super.setMaterial(mat);
if (getChild(0) != null) {
getChild(0).setMaterial(mat);
}
System.out.println("Attempted to set material for " + getName() + “!!\n”
+ "Mat’s name: " + mat.getName() + (mat.getTextureParam(“DiffuseMap”) != null ? "\nMat’s tex name: " + mat.getTextureParam(“DiffuseMap”).getTextureValue().getName() : “”));
}
[/java]

Hope that makes a little bit more sense.

I don’t think Image.clone() works like you think it does:
http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/texture/Image.java#392

@pspeed You are right. But, even after removing that it won’t fix the problem. I manually set the image to black anyway so that wouldn’t make a difference. However, just to test it I did remove all .clone() calls, even on other types and the problem is still there. Thanks for that tip though.

@vinexgames said: @pspeed You are right. But, even after removing that it won't fix the problem. I manually set the image to black anyway so that wouldn't make a difference. However, just to test it I did remove all .clone() calls, even on other types and the problem is still there. Thanks for that tip though.

It looks to me like you are sharing the same image data over and over. clone() didn’t fix the issue but the issue is still there. The problem isn’t using clone() the problem is that clone() isn’t fixing the problem you were trying to solve by calling clone().

1 Like

I’m reloading the image and texture each time, and besides that It should still paint the correct textures over the previous. I output the name of the texture that’s loaded for each part (for example, Base1_main, or Top2_extra), and it always correctly corresponds to the model I’m trying to texture. When I get home I’m gonna try removing any colorizing of the textures with DefaultImageRaster to see if it can just load the textures without mixing it up. That’ll tell me if it’s a problem with loading the textures. If that works, I’ll try only coloring them one color. I’ll also try to mess with ImagePainter again and see if I can’t figure it out this time. If none of these fix the issue, I’ll probably just remove custom colors until I can figure it out.

I feel like we are talking in circles.

This call:
[java]Texture tempTex = AssetLoading.getAssetManager().loadTexture(“Textures/Weapons/Template.png”).clone();[/java]

Loads the same image data buffer every time. If you draw to it then it will affect all of the previous ones that you loaded… no matter how many times you clone it, the underlying image buffers are shared unless you specifically clone those buffers and create a new image.

So I don’t know if this is the problem you were complaining about but it is a problem. If you load that texture and paint it orange then load it again and paint it blue then all of the objects using the texture will now be blue.

Just throwing 2c in here, tell me to shush if I’m off track :wink:

Sounds like you need to have the template stored but not used, each time you want to create the new image (clone) then just create and brand new blank image (no loading: all new) then manually copy the contents of the template into it and then use the new image to set the color. (ie for loops > get pixel from template & use it to set pixel on the new image changing/setting the color as needed) That’s if you are using the template to tell the code where to set the colors, but if you are blacking out the whole image then why load a template? just create a new image and blank it?
This way your spatials/models/objects will each be using their own texture set and not be sharing buffers/images as pspeed says.

Make any sense?
As I said, just throwing ideas in just in case it helps.

(EDIT) I use this to create my new images:
[java]
// Create a new blank image as RGBA8 (4 bytes per pixel)
Image imgAlphaMap = new Image(Image.Format.RGBA8, tileQuadSize,
tileQuadSize, ByteBuffer.allocate(tileQuadSizetileQuadSize4));
[/java]

@radanz

SideTip:
Dont call ByteBuffer.allocated manually, use BufferUtils from the jme utils, it will allow you to do tracking later, if you ever run into out of direct memory errors.

@Empire Phoenix said: @radanz SideTip: Dont call ByteBuffer.allocated manually, use BufferUtils from the jme utils, it will allow you to do tracking later, if you ever run into out of direct memory errors.

Ahh cool, thanks, amended example would then be:

[java]
// Create a new blank image as RGBA8 (4 bytes per pixel)
Image imgAlphaMap = new Image(Image.Format.RGBA8, tileQuadSize,
tileQuadSize, BufferUtils.createByteBuffer(tileQuadSizetileQuadSize4));
[/java]
I think… :wink:

@pspeed I’ll have to look at that.

@radanz I’ll definitely give that a try.

Thanks for all the help!

ImagePainter will also create a new image for you if you want - it’s one of the constructors.

Although it was using allocate direct not createByteBuffer - I’ll change that :slight_smile:

@zarch I’ll be using ImagePainter to paint in details like scratches and stuff. :slight_smile:

@radanz Your solution worked! Thanks so much! I can now play my game with a strange, otherworldly sniper rifle which is red, green, blue, and pretty much any other color you can think of. Thanks again! :smiley: