Sure, here it is:
package com.threed.jpct.util;
import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.Object3D;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
/**
* A simple lens flare effect. You need four different textures for this, one burst and three halos. How
* to create/get these textures is up to you. jPCT doesn't come with any.
* @author EgonOlsen
*/
public class LensFlare implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Texture burst=null;
private Texture halo1=null;
private Texture halo2=null;
private Texture halo3=null;
private SimpleVector sunPos=null;
private Texture[] types=new Texture[7];
private float[][] scales=new float[7][2];
private float globalScale=1;
private int trans=1;
private boolean cover=true;
private float maxDistance=-1;
private boolean revertDirection=false;
private boolean visible=false;
private SimpleVector light2D=null;
private SimpleVector tmp1=new SimpleVector();
private SimpleVector tmp2=new SimpleVector();
private SimpleVector tmp3=new SimpleVector();
/**
* Create a new lens flare for a light source.
* @param lightPos the position of the light source
* @param burst the name of the burst texture as added to the TextureManager
* @param halo1 the name of the first halo texture as added to the TextureManager
* @param halo2 the name of the second halo as added to the TextureManager
* @param halo3 the name of the third halo texture added to the TextureManager
*/
public LensFlare(SimpleVector lightPos, String burst, String halo1, String halo2, String halo3) {
TextureManager tm=TextureManager.getInstance();
this.burst=tm.getTexture(burst);
this.halo1=tm.getTexture(halo1);
this.halo2=tm.getTexture(halo2);
this.halo3=tm.getTexture(halo3);
this.sunPos=new SimpleVector(lightPos);
types[0]=this.burst;
types[1]=this.halo1;
types[2]=this.burst;
types[3]=this.halo2;
types[4]=this.burst;
types[5]=this.halo3;
types[6]=this.burst;
scales[0][0]=1;
scales[0][1]=1;
scales[1][0]=2;
scales[1][1]=0.5f;
scales[2][0]=3;
scales[2][1]=0.25f;
scales[3][0]=8;
scales[3][1]=1;
scales[4][0]=-2;
scales[4][1]=0.5f;
scales[5][0]=-4;
scales[5][1]=0.25f;
scales[6][0]=-5.5f;
scales[6][1]=0.25f;
}
/**
* Sets the transparency of the effect.
* @param trans the transparency. 0 is lowest,
*/
public void setTransparency(int trans) {
this.trans=trans;
}
/**
* Sets a new light position.
* @param lightPos the new position
*/
public void setLightPosition(SimpleVector lightPos) {
sunPos.set(lightPos);
}
/**
* Sets the global scale of the effect.
* @param scale the scale
*/
public void setGlobalScale(float scale) {
globalScale=scale;
}
/**
* If true (default), all geometry that is a potential collider hides the effect if it's located in
* a direct line between the camera and the light source.
* @param hides should geometry hide it or not?
*/
public void setHiding(boolean hides) {
cover=hides;
}
/**
* If hiding is enabled, this value specifies how far away from the camera a polygon can maximally be
* to be considered as a blocker. Anything farer away can't hide the effect. Lowering this value can improve
* performance but may lead to flares where non should be. -1 is default, which means no limits.
* @param distance the distance
*/
public void setMaximumDistance(float distance) {
this.maxDistance=distance;
}
/**
* If hiding is enabled, the visibility calculations can be done camera->light (default) or light->camera. Depending
* on the scene, one or the other will be faster.
* @param lightToCam do it light->camera or vice versa
*/
public void setDirection(boolean lightToCam) {
revertDirection=lightToCam;
}
/**
* Updates the lens flare. Skipping this method and calling render only will cause the lens flare to remain static.
* This method should be called if either the camera or, if hiding is enabled, the hiding objects are moving.
* @param buffer the frame buffer
* @param world the world
*/
public void update(FrameBuffer buffer, World world) {
Camera cam=world.getCamera();
light2D=Interact2D.project3D2D(cam, buffer, sunPos, tmp3);
visible=true;
if (cover) {
SimpleVector camPos=cam.getPosition(tmp1);
if (!revertDirection) {
// From camera to light
SimpleVector delta=camPos;
tmp2.set(camPos);
delta.scalarMul(-1);
delta.add(sunPos);
float dlen=delta.length();
float dist=world.calcMinDistance(tmp2, delta.normalize(delta), maxDistance!=-1?Math.min(maxDistance, dlen*1.05f):dlen*1.05f);
//System.out.println("1: "+ dist+"/"+(dlen-5));
visible=(dist==Object3D.COLLISION_NONE || dist>dlen-5);
} else {
// From light to camera
tmp2.set(sunPos);
tmp2.scalarMul(-1);
SimpleVector delta=camPos;
delta.add(tmp2);
float dlen=delta.length();
float dist=world.calcMinDistance(sunPos, delta.normalize(delta), maxDistance!=-1?Math.min(maxDistance, dlen*1.05f):dlen*1.05f);
visible=(dist==Object3D.COLLISION_NONE || dist>dlen-5);
//System.out.println("2: "+ dist+"/"+(dlen-5));
}
}
}
/**
* Renders the effect.
* @param buffer the frame buffer
*/
public void render(FrameBuffer buffer) {
if (light2D!=null && visible) {
SimpleVector lp=tmp1;
lp.set(light2D);
float mx=buffer.getCenterX();
float my=buffer.getCenterY();
lp.z=0;
SimpleVector cp=tmp2;
cp.set(mx,my,0);
cp.scalarMul(-1);
lp.add(cp);
SimpleVector dir=lp;
float len=dir.length();
dir=dir.normalize(dir);
SimpleVector d=tmp2;
d.set(0, 0, 0);
for (int i=0; i<types.length; i++) {
d.set(dir);
Texture t=types[i];
float l=scales[i][0];
float scale=scales[i][1]*globalScale;
d.scalarMul((1f/l)*len);
int tw=t.getWidth();
int th=t.getHeight();
int x=(int)(d.x-((tw>>1)*scale));
int y=(int)(d.y-((th>>1)*scale));
buffer.blit(t, 0, 0, x+(int)mx, y+(int)my, tw, th, (int)((float)tw*scale), (int)((float)th*scale), trans, true, RGBColor.WHITE);
}
}
}
}