Hi, i'm quite new here, I would like to share this tiny but useful (I hope) class that compose many images in ony one.
The idea is to use it to compose the face of a pg using eyes, hairs etc etc, or to generate random trees, or grass.
have fun!
(and ask for any problems!!)
/*
* @author Marco Servetto
* @date 16/02/2008
*
* */
package base;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.swing.ImageIcon;
import com.jme.image.Texture;
import com.jme.util.TextureManager;
/*
* This class Generate a texture from a set of image and positions.
* It uses a percentage representation for placing images on the texture.
* For example
* add(i,1.0f,1.0f,0.5f,0.5f,0) cover the the texture all with i
* add(i,0.1f,0.1f,0.5f,0.5f,0) place i at the center of the texture, big as 1/10 of the texture size.
* add(i,0.2f,0.2f,0.1f,0.1f,0) place i near to the left top corner of the texture, big as 2/10 of the texture size.
* add(i,0.1f,0.1f,0.9f,0.9f,PI/2f) place i near to the right bottom corner of the texture, big as 1/10 of the texture size,with 90 degrees of rotation.
*
* */
public class ProceduralTextureComposition {
BufferedImage imgBuffer;
Graphics2D g;
/*
* type can be BufferedImage.TYPE_INT_ARGB or
* BufferedImage.TYPE_INT_RGB or
* other in the same family.
* */
public ProceduralTextureComposition(int width,int height,int type){
imgBuffer = new BufferedImage(width,height,type);
g=(Graphics2D)imgBuffer.getGraphics();
}
/* examples
* add(i,1.0f,1.0f,0.5f,0.5f,0) cover the the texture all with i
* add(i,0.1f,0.1f,0.5f,0.5f,0) place i at the center of the texture, big as 1/10 of the texture size.
* add(i,0.2f,0.2f,0.1f,0.1f,0) place i near to the left top corner of the texture, big as 2/10 of the texture size.
* add(i,0.1f,0.1f,0.9f,0.9f,PI/2f) place i near to the right bottom corner of the texture, big as 1/10 of the texture size,with 90 degrees of rotation.
* */
public void add(ImageIcon i,float scaleX,float scaleY,float posX,float posY,float alpha){
place(imgBuffer,g,i,scaleX,scaleY,posX,posY,alpha);
}
/* examples
* add(i,1.0f,1.0f,0.5f,0.5f,0) cover the the texture all with i
* add(i,0.1f,0.1f,0.5f,0.5f,0) place i at the center of the texture, big as 1/10 of the texture size.
* add(i,0.2f,0.2f,0.1f,0.1f,0) place i near to the left top corner of the texture, big as 2/10 of the texture size.
* add(i,0.1f,0.1f,0.9f,0.9f,PI/2f) place i near to the right bottom corner of the texture, big as 1/10 of the texture size,with 90 degrees of rotation.
* */
public void add(URL url,float scaleX,float scaleY,float posX,float posY,float alpha){
place(imgBuffer,g,new ImageIcon(url),scaleX,scaleY,posX,posY,alpha);
}
/*
* Compute and return the texture.
* */
public Texture generateTexture(){
g.dispose();
return TextureManager.loadTexture(imgBuffer, Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true );
}
private static AffineTransform findPlace(double scaleX,double scaleY,double posX,double posY,double alpha,double sizeX,double sizeY,double imgX,double imgY){
AffineTransform m=new AffineTransform();
m.concatenate(AffineTransform.getTranslateInstance(posX,posY));
m.concatenate(AffineTransform.getRotateInstance(alpha));
m.concatenate(AffineTransform.getScaleInstance(scaleX,scaleY));
m.concatenate(AffineTransform.getTranslateInstance(-imgX/2d,-imgY/2d));
return m;
}
private static void place(BufferedImage imgBuffer,Graphics2D g,ImageIcon i,float scaleX,float scaleY,float posX,float posY,float alpha){
double sizeX=imgBuffer.getWidth();
double sizeY=imgBuffer.getHeight();
double imgX=i.getIconWidth();
double imgY=i.getIconHeight();
double absScaleX=(sizeX/imgX)*scaleX;
double absScaleY=(sizeY/imgY)*scaleY;
double absPosX=sizeX*posX;
double absPosY=sizeY*posY;
double absAlpha=alpha;
g.drawImage(i.getImage(),findPlace(absScaleX,absScaleY,absPosX,absPosY,absAlpha,sizeX,sizeY,imgX,imgY),null);
}
}
The follow is a running example
package base;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import com.jme.app.SimpleGame;
import com.jme.math.FastMath;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.TextureState;
public class TestImageIconComposition extends SimpleGame {
public static void main(String[]s){
SimpleGame app=new TestImageIconComposition();
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
@Override
protected void simpleInitGame() {
ProceduralTextureComposition p=new ProceduralTextureComposition(2500,2500,BufferedImage.TYPE_INT_ARGB);
//p.add(EnchantedLoader.getResource("FOGLIEgmp4.png"),0.1f,0.1f,0.5f,0.5f,0);
ImageIcon i=new ImageIcon(EnchantedLoader.getResource("FOGLIEgmp4.png"));
for(int ii= 2000;ii>0;ii--){
float scale=0.08f+FastMath.nextRandomFloat()/30f;
p.add(i,scale,scale,FastMath.nextRandomFloat(),FastMath.nextRandomFloat(),FastMath.nextRandomFloat()*FastMath.PI);
}
Quad q=new Quad("prova",100,100);
Quad q2=new Quad("prova2",100,100);
q2.setLocalTranslation(0,0, -1);
TextureState ts = display.getRenderer().createTextureState();
ts.setEnabled(true);
ts.setTexture(p.generateTexture());
q.setRenderState(ts);
Activate.alpha(q);
rootNode.attachChild(q);
rootNode.attachChild(q2);
}
}
and that is a screeenshot of the results
http://picasaweb.google.com/marco.servetto/JmeData/photo#5167646176588833506
and this is the starting leaf

http://picasaweb.google.com/marco.servetto/JmeData/photo#5167646180883800818
Can you imagin the result with better starting image, and more than one type of leaf? :)