Okay, I'll explain.
I'm combining some 2D java.awt ideas with JPCT, so my display() method looks like this:
private void display() {
//create an image which is drawn in the Frame later
//frame is declared as a java.awt.Frame. width and height are the dimensions of the frame.
Image im=frame.createImage(width,height);
Graphics g=im.getGraphics();
//draws the world using the software renderer
buffer.display(g, leftBorderWidth, titleBarHeight);
/*here I did a selection sort of the portals in the order of their distance from the camera,
but that's rigorous info I can leave out*/
/*draws the portals. The 'portals' variable is declared as java.util.LinkedList<Portal> portals,
and the Portal class is shown below*/
for (int i=0;i<portals.size();i++)
{
Portal current=portals.get(i);
//We don't want to draw portals if we're miles away, so we get the distance to 'current'
SimpleVector camToPortal=current.structure.getTransformedCenter();
camToPortal.sub(camera.getPosition());
if (camToPortal.length()<PORTAL_DISCARD_DISTANCE)
{
/*just plain ol' java.awt. Any objects in the foreground that could get in front of the portal
could probably be put in another World object, which we could render after the portals are drawn*/
Polygon p=current.getPolygon();
g.setClip(p);
g.drawImage(current.getImage(),0,0,frame);
}
}
gFrame.drawImage(im,0,0,frame);
}
And this is my Portal class:
import com.threed.jpct.*;
import java.awt.*;
public class Portal{
//An Object3D representing the portal, but we never add it to the world.
Object3D structure;
//The portal that this portal leads to
Portal dest=null;
//Used to manipulate coordinates of the vertices in the portal's polygons.
GenVertContr gvc=new GenVertContr();
//The coordinates of the vertices in the portal's polygons
SimpleVector []threeDs=null;
//the angles that this portal is rotated about the x, y, and z axes.
float dx=0;
float dy=0;
float dz=0;
//x,y,z are the coordinates. dx, dy, and dz are the angles that the portals is rotated about the x, y, and z axes.
public Portal(float x, float y, float z, float dx, float dy, float dz)
{
//I would load the structure once, and I'd clone that structure for every new portal.
//But this will work too.
structure=Loader.load3DS("Portal.3ds", 10);
if (objs.length>0)
{
structure=objs[0];
for (int i=1;i<objs.length;i++)
{
structure=Object3D.mergeObjects(portalObj, objs[i]);
}
}
structure.enableLazyTransformations();
//if you're taking the cloning approach, you'd have to clone the mesh as well before the next line
structure.getMesh().setVertexController(gvc, true);
//place the portal
structure.translate(x,y,z);
//rotate the portal. I forget why, but structure.rotateX() rotateY() and rotateZ() yield different results.
structure.rotateAxis(new SimpleVector(1,0,0), dx);
structure.rotateAxis(new SimpleVector(0,1,0), dy);
structure.rotateAxis(new SimpleVector(0,0,1),dz);
this.dx=dx;
this.dy=dy;
this.dz=dz;
//get the coordinates of the vertices, and place them to where they would be in the world.
threeDs=gvc.getSourceMesh();
for (int i=0;i<gvc.getMeshSize();i++)
{
threeDs[i].rotate(structure.getRotationMatrix());
threeDs[i].add(structure.getTransformedCenter());
}
}
//Links two portals together.
public void setDest(Portal dest)
{
this.dest=dest;
//sometimes we might not want this to be the case, but usually we will.
dest.dest=this;
}
//Here's the tricky part. Getting the image of what the other portal's seeing
public Image getImage()
{
/*Before we go any further, take note that the class that has display(),
and it has the World, the Frame, the FrameBuffer etc is called Main*/
Image im=Main.frame.createImage(Main.frame.getWidth(),Main.frame.getHeight());
Graphics g=im.getGraphics();
//Hang on to your head
Camera cam=Main.world.getCamera();
//Climb out of your head and see the world from the dest portal's eyes
Main.world.newCamera();
Camera newCam=Main.world.getCamera();
//the core geometry
SimpleVector camToSrc=structure.getTransformedCenter().calcSub(cam.getPosition());
camToSrc.rotateX(dx-dest.dx);
camToSrc.rotateY(dest.dy-dy);
newCam.setPosition(dest.structure.getTransformedCenter().calcSub(camToSrc));
SimpleVector lookAt=cam.getDirection();
lookAt.rotateX(dx-dest.dx);
lookAt.rotateY(dest.dy-dy);
lookAt.add(newCam.getPosition());
newCam.lookAt(lookAt);
newCam.rotateCameraZ(dest.dz-dz);
//draw the world from dest's view into im's graphics instance.
Main.buffer.clear(Main.skyColor);
Main.world.renderScene(Main.buffer);
Main.world.draw(Main.buffer);
Main.buffer.update();
Main.buffer.display(g, Main.leftBorderWidth, Main.titleBarHeight);
//don't forget to climb back into your own head
Main.world.setCameraTo(cam);
//we've got what we need
return im;
}
public Polygon getPolygon()
{
Polygon p=new Polygon();
addPoint(p,0);
addPoint(p,2);
addPoint(p,12);
addPoint(p,14);
/*... there were 98 of these, and they're not in any particular order.
I found some way to number all the vertices and draw them in another frame, then I could see where each point is,
and which order they would need to be added in order to create a non-self-intersecting polygon*/
return p;
}
private void addPoint(Polygon p,int index)
{
try
{
SimpleVector twoD=Interact2D.project3D2D(Main.camera, Main.buffer, threeDs[index]);
p.addPoint((int)twoD.x, (int)twoD.y);
}
catch(NullPointerException e)
{
}
catch(ArrayIndexOutOfBoundsException e)
{
}
}
public class GenVertContr extends GenericVertexController
{
@Override
public void apply() {
}
}
}
Any questions? I hope that wasn't too rigorous.