jPCT dose not support jogl 2.1.5

Started by iamfoolberg, August 27, 2015, 05:16:40 AM

Previous topic - Next topic

iamfoolberg

Since jogl 2.1.5 have many refactors on GL* classes, jPCT' glfacade can not  find the old classes in old version jogl.
Actually, it is a simple task to update jPCT and glfacade for new jogl version.

Would u plz modify them and release new versions.

Or you may make them open source, i can do that quickly:)

Forgive my Chinglish:)

EgonOlsen

#1
That's actually not a bug. I just didn't care to support because I got no reports from people that are actually using this solution nor does anybody requested a version for 2.x. Anyway, here you go: http://jpct.de/download/src/glfacade.zip

It would be nice, if you could return the version for 2.x to me, so that I can include it and everybody can benefit from it.

Edit: You'll need these two from the com.threed.jpct-package as well: http://jpct.de/download/src/addones.zip

EgonOlsen

BTW: I haven't tested this facade code for a while. There's a small chance that it misses some methods that newer versions of jPCT are using. If you encounter such thing, please let me know...thanks!

iamfoolberg

I want to integrate some 3d engine into NASA WorldWind, so that i can load 3d models and animations.
Now, WW uses jogl 2.1.5 in my configuration.
And i think jPCT is a nice work for that purpose.

I'll try your suggestions and post my result.

thx.

iamfoolberg

After modifying about ten lines, the new glfacade seems to be working.
I run the HelloWorldAWTGL without lwjgl jars, it works(and tell me the jogl is injected).

But the HelloWorldOGL can not run, the errors are:

Loading Texture...from InputStream
Java version is: 1.8.0_45
-> support for BufferedImage
Version helper for 1.5+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Software renderer disposed
Exception in thread "main" java.lang.NoClassDefFoundError: org/lwjgl/opengl/Display
   at com.threed.jpct.GLHelper.findMode(GLHelper.java:67)
   at com.threed.jpct.GLHelper.findMode(GLHelper.java:62)
   at com.threed.jpct.GLHelper.init(GLHelper.java:160)
   at com.threed.jpct.GLRenderer.init(GLRenderer.java:24)
   at com.threed.jpct.FrameBuffer.enableRenderer(FrameBuffer.java:1134)
   at com.threed.jpct.FrameBuffer.enableRenderer(FrameBuffer.java:753)
   at com.threed.jpct.FrameBuffer.enableRenderer(FrameBuffer.java:700)
   at helloworld.HelloWorldOGL.loop(HelloWorldOGL.java:41)
   at helloworld.HelloWorldOGL.main(HelloWorldOGL.java:19)
Caused by: java.lang.ClassNotFoundException: org.lwjgl.opengl.Display
   at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
   ... 9 more

the org.lwjgl.opengl.Display can not be found in glfacade, it is in lwjgl.jar, but how can we find it when that jar excluded.
i comment the lines in the HelloWorldOGL to make it runnable.

All files are in attachment.

I manage them in maven-Eclipse.
Don't forget to replace the JOGLCanvas and JOGLRenderer in the jPCT project.

I really hope that the main jPCT project can be open sourced.

EgonOlsen

The HelloWorldOGL isn't supposed to work with Jogl. It renders to a native window and not into a canvas. Jogl doesn't support this. The only way to use it is to use the AWTGLRenderer.

iamfoolberg

Thanks EgonOlsen, but i get another question to draw models in WorldWind with jPCT.

Accroding to WW's docs, i should implement the integration by implementing an interface(i.e. gov.nasa.worldwind.layers.Layer). So i extends an AbstractLayer who implemented the Layer.
And i should draw the models in jPCT to the provided GL2/3/4 object.
The code seems as follows:


package org.aoe.det.ww.d3man.ww;

import java.lang.reflect.Field;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;

import org.gbzh.util.resource.Resource;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.render.DrawContext;

public class Jpct3DLayer extends AbstractLayer {
/** The world of jPCT. */
private World world;
/***/
private FrameBuffer buffer;
private GL2 lastGL;

public Jpct3DLayer() {
this.world = new World();
this.world.setAmbientLight(0, 255, 0);

TextureManager.getInstance().addTexture("box", new
Texture(Resource.getResource("data/POLYSHIP.jpg")));

Object3D box = Primitives.getBox(13f, 2f);
box.setTexture("box");
box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

this.world.getCamera().setPosition(50, -50, -5);
SimpleVector point = new SimpleVector(0.0, 0.0, 0.0);
this.world.getCamera().lookAt(point);// box.getTransformedCenter()

this.buffer = new FrameBuffer(800, 600,
FrameBuffer.SAMPLINGMODE_NORMAL);
this.buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
this.buffer.enableRenderer(IRenderer.RENDERER_OPENGL,
IRenderer.MODE_OPENGL);

}

private void injectGL(GL gl) {
String[] classes = new String[] {
"org.lwjgl.opengl.GL11",
"org.lwjgl.opengl.GL15",
"org.lwjgl.opengl.GL20",
"org.lwjgl.opengl.Util",
"org.lwjgl.opengl.ARBMultitexture",
"org.lwjgl.opengl.EXTFramebufferObject",
"org.lwjgl.opengl.ARBShaderObjects",
"org.lwjgl.opengl.GLContext" };
Class<?> clazz;
for (int i = 0; i < classes.length; i++) {
try {
clazz = Class.forName(classes[i]);
Field glf = clazz.getDeclaredField("gl");
glf.set(clazz, gl);
} catch (Exception e) {
Logger.log("Unable to inject GL context into the facade!",
Logger.ERROR);
}
}
}

@Override
protected void doRender(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();
if (this.lastGL != gl) {
this.injectGL(gl);
this.lastGL = gl;
}

// jPCT should draw its world with the given gl
this.repaint();
}

/**
* force this layer to redraw components inside it.
*/
public void repaint() {
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
}
}



I excluded the lwjgl.jars, but get the following error(the same as that in my last reply) when adding this layer to WW.

[ Sun Aug 30 21:01:13 CST 2015 ] - WARNING: Unsupported Texture width (260)...resizing to a width of 256 pixels!
Java version is: 1.8.0_45
-> support for BufferedImage
Version helper for 1.5+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Software renderer disposed
Exception in thread "main" java.lang.NoClassDefFoundError: org/lwjgl/opengl/Display
   at com.threed.jpct.GLHelper.findMode(GLHelper.java:67)
   at com.threed.jpct.GLHelper.findMode(GLHelper.java:62)
   at com.threed.jpct.GLHelper.init(GLHelper.java:160)
   at com.threed.jpct.GLRenderer.init(GLRenderer.java:24)
   at com.threed.jpct.FrameBuffer.enableRenderer(FrameBuffer.java:1134)
   at com.threed.jpct.FrameBuffer.enableRenderer(FrameBuffer.java:753)
   at org.aoe.det.ww.d3man.ww.Jpct3DLayer.<init>(Jpct3DLayer.java:51)
   at org.aoe.det.ww.d3man.D3ManDemoApp$DemoAppFrame.<init>(D3ManDemoApp.java:68)
   at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
   at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
   at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
   at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
   at java.lang.Class.newInstance(Class.java:442)
   at gov.nasa.worldwindx.examples.ApplicationTemplate.start(ApplicationTemplate.java:294)
   at org.aoe.det.ww.d3man.D3ManDemoApp.main(D3ManDemoApp.java:79)
Caused by: java.lang.ClassNotFoundException: org.lwjgl.opengl.Display
   at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

That is to say, jPCT uses the class org.lwjgl.opengl.Display in somewhere.
How can i remove the dependency and use the pure jogl class?

EgonOlsen

That's because you are using the wrong enable-method. To use Jogl or lwjgl's canvas, you have to use enableGLCanvasRenderer instead. Just like the awtgl-example should do it.

iamfoolberg

Thanks EgonOlsen again.
I change my program and it runs without the "NoClassDefFoundError".
But my next question is, where is my 3d box:)

As in the following code, i set the box on the surface of the earth, and the camera alittle higher than it.
But i can not find the box in WorldWind.


package org.aoe.det.ww.d3man.ww;

import java.awt.Canvas;
import java.lang.reflect.Field;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.swing.JFrame;

import org.aoe.det.ww.d3man.D3Man;
import org.gbzh.util.log.Log;
import org.gbzh.util.resource.Resource;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.render.DrawContext;
/**
* A jPCT based three model layer.
* In jPCT, positive x goes to the right,
* positive z goes INTO the screen
* and positive y goes DOWN.
* @author berg
*
*/
public class Jpct3DLayer extends AbstractLayer {
/** The world of jPCT. */
private World world;
/***/
private FrameBuffer buffer;
private GL2 lastGL;
private Canvas canvas;
private Object3D box;
private float move = 0.0f;

private float surfaceElevation = 6378137.0f;
private SimpleVector boxLoc = new SimpleVector(0, 0, -(surfaceElevation+50000));
private SimpleVector cameraLoc = new SimpleVector(0, 0, -(surfaceElevation+50000+100));
public Jpct3DLayer() {
this.world = new World();
this.world.setAmbientLight(0, 255, 0);

TextureManager.getInstance().addTexture("box",
new Texture(Resource.getResource("data/POLYSHIP.jpg")));

box = Primitives.getBox(13f, 2f);
box.setTexture("box");
box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

box.translate(boxLoc);
this.world.getCamera().setPosition(cameraLoc);
SimpleVector point = new SimpleVector(0.0, 0.0, 0.0);
this.world.getCamera().lookAt(point);
this.world.getCamera().setFOV(this.world.getCamera().getMaxFOV());

this.buffer = new FrameBuffer(800, 600,
FrameBuffer.SAMPLINGMODE_NORMAL);

canvas = buffer.enableGLCanvasRenderer();
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
}

// puts opengl in the correct state for this layer
protected void beginDraw(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();

gl.glPushAttrib(GL2.GL_TEXTURE_BIT | GL2.GL_ENABLE_BIT
| GL2.GL_CURRENT_BIT | GL2.GL_TRANSFORM_BIT);

if (!dc.isPickingMode()) {
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
}

gl.glMatrixMode(javax.media.opengl.GL2.GL_MODELVIEW);
gl.glPushMatrix();

//inject gl if neccessary
if (this.lastGL != gl) {
this.injectGL(gl);
this.lastGL = gl;
}
}

// resets opengl state
protected void endDraw(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();

gl.glMatrixMode(javax.media.opengl.GL2.GL_MODELVIEW);
gl.glPopMatrix();

gl.glPopAttrib();
}

private void injectGL(GL gl) {
String[] classes = new String[] {
"org.lwjgl.opengl.GL11",
"org.lwjgl.opengl.GL15",
"org.lwjgl.opengl.GL20",
"org.lwjgl.opengl.Util",
"org.lwjgl.opengl.ARBMultitexture",
"org.lwjgl.opengl.EXTFramebufferObject",
"org.lwjgl.opengl.ARBShaderObjects",
"org.lwjgl.opengl.GLContext" };
Class<?> clazz;
try {
for (int i = 0; i < classes.length; i++) {
clazz = Class.forName(classes[i]);
Field glf = clazz.getDeclaredField("gl");
glf.set(clazz, gl);
}
Log.d("gl injected.");
} catch (Exception e) {
Logger.log("Unable to inject GL context into the facade!",
Logger.ERROR);
}
}

/**
* Called by WorldWind to refresh this layer.
*/
@Override
protected void doRender(DrawContext dc) {
System.out.println("move="+move);
this.beginDraw(dc);

GL2 gl = (GL2) dc.getGL();
//get the WW position of the box.
Position position = D3Man.getInstance().translatePosition(
boxLoc.x, boxLoc.y, -boxLoc.z);
Vec4 loc = dc.getGlobe().computePointFromPosition(position);
double size = this.computeSize(dc, loc);

//move the box a little
move = move - 1;
box.translate(0, 0, move);

//save current gl settings before change it
dc.getView().pushReferenceCenter(dc, loc);

//adjust current gl settings for jPCT's world
gl.glRotated(position.getLongitude().degrees, 0, 1, 0);
gl.glRotated(-position.getLatitude().degrees, 1, 0, 0);
gl.glScaled(size, size, size);

// jPCT draw its world with the given gl
this.repaint();

//restore last gl settings
dc.getView().popReferenceCenter(dc);
this.endDraw(dc);
}

private double computeSize(DrawContext dc, Vec4 loc) {
if (loc == null) {
System.err.println("Null location when computing size of mode");
return 1;
}
double d = loc.distanceTo3(dc.getView().getEyePoint());
double size = 60 * dc.getView().computePixelSizeAtDistance(d);
if (size < 2)
size = 2;

return size;
}

/**
* force this layer to redraw components inside it.
*/
public void repaint() {
buffer.clear(java.awt.Color.GREEN);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
canvas.repaint();
}

public static void main(String[] args) {
JFrame frame=new JFrame("Hello world");
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

Jpct3DLayer layer = new Jpct3DLayer();
frame.add(layer.canvas);

float x = 0f;
float y = 0f;
float z = 0f;
while (frame.isShowing()) {
layer.box.rotateY(0.1f);
y += 0.2f;
SimpleVector sv = new SimpleVector(x, y, z);
layer.box.translate(sv);
layer.buffer.clear(java.awt.Color.BLUE);
System.out.println(layer.box.getTranslation());
layer.world.renderScene(layer.buffer);
layer.world.draw(layer.buffer);
layer.buffer.update();
layer.buffer.displayGLOnly();
layer.canvas.repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


In the posted code, WW calls the doRender method and gives us a DrawContext where we can find the GL2 object.
I inject the GL2 object to jPCT classes.
I think it is a question about coordination transforming, but how can i get the right transformation to let jPCT
draw the box with WW's GL2?

BTW, the code can be run as a simple java app, with its main() method.

PS: Should i open another post to ask this question?

EgonOlsen

Not sure...the mix between direct GL calls and jPCT scares me, because it's really hard to see if they don't interfere in some way. Anyway, if your WW coordinates are actual OpenGL coordinates, the jPCT equivalent would be (x, -y, -z): http://www.jpct.net/wiki/index.php?title=Coordinate_system.
I'm not sure if that's your actual issue though...

iamfoolberg

#10
Good news is i can see jPCT's box in another JFrame, which take jPCT's canvas as its child.
Bad news is i still can not draw the canvas to the WW's gl.

I adjust the coordinates with some methods, and stick the box before the eye point of WW,
and set the jPCT's camera at the eye point at any time. So i can see the box, no matter where the eye point and camera is.

But when i paint the canvas to a BufferedImage, which will be drawn to WW' gl, NOTHING is drawn into the image.

I guess in jPCT, the world/scence is not drawn into the gl injected directly, but in the buffered canvas.
And the canvas(JOGLCanvas in my debugger) did not paint itself to the given image's Graphics.

I wonder how can i make jPCT draw the scence directly into the gl injected, or how can i "copy" the canvas into the image, which will be drawn into the WW's gl.

A runtime screeshot is in the attachment.

And the code:

package org.aoe.det.ww.d3man.ww;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.Arrays;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.swing.JFrame;

import org.aoe.det.ww.d3man.D3Man;
import org.gbzh.util.log.Log;
import org.gbzh.util.resource.Resource;

import com.jogamp.opengl.util.texture.TextureCoords;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.pick.PickedObject;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.util.OGLStackHandler;

/**
* A jPCT based three model layer. In jPCT, positive x goes to the right,
* positive z goes INTO the screen and positive y goes DOWN. In worldwind,
* positive x goes to the right, positive z goes OUT the screen and positive
* goes UP. In worldwind,cartesian coordinates's point(0, 0, radius of the
* earth) has the longi/lati-tude position(0, 0, radius of the earth). longitude
* goes RIGHT to +180 and left to -180, latitude goes UP to +90 and down to -90.
*
* @author berg
*
*/
public class Jpct3DLayer extends AbstractLayer {
/** The world of jPCT. */
private World world;
/***/
private FrameBuffer buffer;
private GL2 lastGL;
private Canvas canvas;
private Object3D box;
private float move = 0.0f;

private double surfaceElevation = 6378137.0;

// in Beijing
// (8830275.0,-8099939.5,4351104.0)
private Vec4 boxLoc = new Vec4(0, 0, 0);
// (8830413.0,-8100067.0,4351172.0)
private Vec4 cameraLoc = new Vec4(0, 0, surfaceElevation);

public Jpct3DLayer() {
this.world = new World();
this.world.setAmbientLight(0, 255, 0);

TextureManager.getInstance().addTexture("box",
new Texture(Resource.getResource("data/POLYSHIP.jpg")));

box = Primitives.getBox(13f, 2f);

box.setTexture("box");
box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

box.translate(ww2jpct(boxLoc));
this.world.getCamera().setPosition(ww2jpct(cameraLoc));

SimpleVector point = new SimpleVector(0.0, 0.0, 0.0);
this.world.getCamera().lookAt(point);
// this.world.getCamera().setFOV(this.world.getCamera().getMaxFOV());

this.buffer = new FrameBuffer(800, 600,
FrameBuffer.SAMPLINGMODE_NORMAL);

canvas = buffer.enableGLCanvasRenderer();
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);

//add a frame, it can show the canvas of jPCT
JFrame frame = new JFrame("Hello world");
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

frame.add(canvas);

new Thread() {
@Override
public void run() {
while (true) {
move -= 10.0;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}.start();
}
private BufferedImage image;
private WritableRaster raster;
private void drawCanvas2Gl(Canvas canvas, GL2 gl) {
method: do {
//try to draw jPCT's canvas to the image
int w,h;
if(image==null){
Rectangle rect = canvas.getBounds();
raster = Raster.createInterleavedRaster(
DataBuffer.TYPE_BYTE, rect.width, rect.height, 4, null);
ComponentColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] { 8, 8, 8, 8 }, true, false,
ComponentColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE);
image = new BufferedImage(colorModel, raster, false,
null);
}
w = image.getWidth();
h = image.getHeight();
Graphics2D g = image.createGraphics();
canvas.paint(g);//NOTHING is draw into the image!

//draw something to check validate method. OK
g.setPaint(Color.RED);
g.setFont(Font.decode("ARIAL-BOLD-50"));

g.drawString(1 + " frames", 10, w / 4);
g.drawString("1 sec", 10, h / 2);
g.drawString(
"Heap:" + Long.toString(Runtime.getRuntime().totalMemory()),
10, 3 * h / 4);
g.dispose();

//draw the image to GL, OK
raster = image.getRaster();
DataBufferByte dukeBuf = (DataBufferByte)raster.getDataBuffer();
            byte[] dukeRGBA = dukeBuf.getData();
            ByteBuffer buffer = ByteBuffer.wrap(dukeRGBA);
            buffer.position(0);
            buffer.mark();

            gl.glBindTexture(GL.GL_TEXTURE_2D, 13);
            gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
            gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
            gl.glTexImage2D (GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, w, h, 0, GL.GL_RGBA,
                    GL.GL_UNSIGNED_BYTE, buffer);

            gl.glEnable(GL.GL_TEXTURE_2D);
            gl.glBindTexture (GL.GL_TEXTURE_2D, 13);
            gl.glBegin (GL2.GL_POLYGON);
            gl.glTexCoord2d (0, 0);
            gl.glVertex2d (0, 0);
            gl.glTexCoord2d(1,0);
            gl.glVertex2d (w, 0);
            gl.glTexCoord2d(1,1);
            gl.glVertex2d (w, h);
            gl.glTexCoord2d(0,1);
            gl.glVertex2d (0, h);
            gl.glEnd ();   
            gl.glFlush();
break method;
} while (false);
}

// puts opengl in the correct state for this layer
protected void beginDraw(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();

gl.glPushAttrib(GL2.GL_TEXTURE_BIT | GL2.GL_ENABLE_BIT
| GL2.GL_CURRENT_BIT | GL2.GL_TRANSFORM_BIT);

if (!dc.isPickingMode()) {
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
}

gl.glMatrixMode(javax.media.opengl.GL2.GL_MODELVIEW);
gl.glPushMatrix();

// inject gl if neccessary
if (this.lastGL != gl) {
this.injectGL(gl);
this.lastGL = gl;
}
}

// resets opengl state
protected void endDraw(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();

gl.glMatrixMode(javax.media.opengl.GL2.GL_MODELVIEW);
gl.glPopMatrix();

gl.glPopAttrib();
}

private void injectGL(GL gl) {
String[] classes = new String[] { "org.lwjgl.opengl.GL11",
"org.lwjgl.opengl.GL15", "org.lwjgl.opengl.GL20",
"org.lwjgl.opengl.Util", "org.lwjgl.opengl.ARBMultitexture",
"org.lwjgl.opengl.EXTFramebufferObject",
"org.lwjgl.opengl.ARBShaderObjects",
"org.lwjgl.opengl.GLContext" };
Class<?> clazz;
try {
for (int i = 0; i < classes.length; i++) {
clazz = Class.forName(classes[i]);
Field glf = clazz.getDeclaredField("gl");
glf.set(clazz, gl);
}
Log.d("gl injected.");
} catch (Exception e) {
Logger.log("Unable to inject GL context into the facade!",
Logger.ERROR);
}
}

/**
* convert WorldWind's Vec4 to jPCT's SimpleVector.
*
* @param x
* @param y
* @param z
* @return
*/
public static SimpleVector ww2jpct(double x, double y, double z) {
return new SimpleVector((float) x, (float) -y, (float) -z);
}

/**
* convert WorldWind's Vec4 to jPCT's SimpleVector.
*
* @param x
* @param y
* @param z
* @return
*/
public static SimpleVector ww2jpct(Vec4 vec) {
return new SimpleVector((float) vec.x, (float) -vec.y, (float) -vec.z);
}

/**
* move the object to the given position, not delta.
*
* @param obj
*            the object to me moved
* @param sv
*            the target position
*/
public static void setObject3DPosition(Object3D obj, SimpleVector sv) {
method: do {
if (sv == null || obj == null) {// 检测是否为空,空则退出
Log.e("The input param sv or obj is null.");
break method;
}
SimpleVector cur = obj.getTranslation();
obj.translate(sv.calcSub(cur));
} while (false);
}

public static void setObject3DPosition(Object3D obj, float x, float y,
float z) {
method: do {
if (obj == null) {// 检测是否为空,空则退出
Log.e("The input param obj is null.");
break method;
}
SimpleVector sv = new SimpleVector(x, y, z);
SimpleVector cur = obj.getTranslation();
obj.translate(sv.calcSub(cur));
} while (false);
}

public static Vec4 jpct2wwPoint(float x, float y, float z) {
return new Vec4(x, -y, -z);
}

public static Vec4 jpct2wwPoint(SimpleVector sv) {
Vec4 result = null;
method: do {
if (sv == null) {// 检测是否为空,空则退出
Log.e("The input param sv is null.");
break method;
}
result = new Vec4(sv.x, -sv.y, -sv.z);
} while (false);
return result;
}

public static SimpleVector ww2jpct(Position position) {
SimpleVector result = null;
method: do {
if (position == null) {// 检测是否为空,空则退出
Log.e("The input param position is null.");
break method;
}
Vec4 vec = D3Man.getInstance().position2Point(position);
result = new SimpleVector((float) vec.x, (float) -vec.y,
(float) -vec.z);
} while (false);
return result;
}

public static Position jpct2wwPosition(float x, float y, float z) {
return D3Man.getInstance().point2Position(x, -y, -z);
}

public static Position jpct2wwPosition(SimpleVector sv) {
Position result = null;
method: do {
if (sv == null) {// 检测是否为空,空则退出
Log.e("The input param sv is null.");
break method;
}
result = D3Man.getInstance().point2Position(sv.x, -sv.y, -sv.z);
} while (false);
return result;
}

/**
* Called by WorldWind to refresh this layer.
*/
@Override
protected void doRender(DrawContext dc) {
this.beginDraw(dc);
// GL initialization checks for GL2
GL2 gl = dc.getGL().getGL2();

// get the eye point of WW, to set the camera in jPCT
// so that jpct's camera go with ww's eye point
Vec4 eyeLoc = dc.getView().getEyePoint();
this.world.getCamera().setPosition(ww2jpct(eyeLoc));
Log.d("eye point = camera position = " + eyeLoc);

Position position = dc.getView().getEyePosition();// D3Man.getInstance().point2Position(boxLoc);
Vec4 loc = dc.getGlobe().computePointFromPosition(position);
double size = 5000;// this.computeSize(dc, loc);

// move the box and adjust the camera
setObject3DPosition(box, ww2jpct(new Position(position.latitude,
position.longitude, position.elevation - 50)));
world.getCamera().lookAt(box.getTranslation());

// save current gl settings before change it
dc.getView().pushReferenceCenter(dc, loc);

// adjust current gl settings for jPCT's world
// gl.glTranslated(-cameraLoc.x, -cameraLoc.y, cameraLoc.z);
// gl.glRotated(position.getLongitude().degrees, 0, 1, 0);
// gl.glRotated(-position.getLatitude().degrees, 1, 0, 0);
// gl.glScaled(size, size, size);
// Log.d("size = "+size);

// jPCT draw its world with the given gl
this.repaint();
//draw canvas to gl
this.drawCanvas2Gl(canvas, gl);
// restore last gl settings
dc.getView().popReferenceCenter(dc);
this.endDraw(dc);
}

private double computeSize(DrawContext dc, Vec4 loc) {
if (loc == null) {
System.err.println("Null location when computing size of mode");
return 1;
}
double d = loc.distanceTo3(dc.getView().getEyePoint());
double size = 600 * dc.getView().computePixelSizeAtDistance(d);
if (size < 2)
size = 2;

return size;
}

/**
* force this layer to redraw components inside it.
*/
public void repaint() {
buffer.clear(Color.BLUE);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
canvas.repaint();
Log.d("box.translation=" + box.getTranslation() + ", camera.position="
+ world.getCamera().getPosition());
}

public static void main(String[] args) {
JFrame frame = new JFrame("Hello world");
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

Jpct3DLayer layer = new Jpct3DLayer();
frame.add(layer.canvas);

Vec4 cameraLoc = new Vec4(0, 0, layer.surfaceElevation);
Vec4 boxLoc;
while (frame.isShowing()) {
// move the camera and the box
cameraLoc = cameraLoc.add3(0, 0, 10000);
boxLoc = cameraLoc.add3(0, 0, 50);
layer.world.getCamera().setPosition(ww2jpct(cameraLoc));
setObject3DPosition(layer.box, ww2jpct(boxLoc));
layer.box.rotateZ(0.1f);
// look at the box
layer.world.getCamera().lookAt(layer.box.getTranslation());
layer.repaint();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


EgonOlsen

This mix of jPCT, GL and canvas still confuses me. Maybe it helps to know that jPCT's canvas renderer doesn't draw directly. It buffers all the GL commands and executes them in the awt event dispatch thread. Maybe doesn't mix well here? Have you tried to do the WW stuff in one of the methods that an IPaintListener implementation provides? Because these will run in awt event dispatch as well. Either before or after the drawing, depending on the method.

iamfoolberg

Actually, i did not look into WW's painting mechanism.
I think WW also caches the gl operations performed in the callback method doRender.
So the best solution is to push all gl operations into WW's gl queue.
But i can not find where the gl operations are performed in jPCT.
I guess the IThreadBuffer is a thread that caches painting opeartions and draws them to gl when called by the EDT.

WW's layer mechanism is quit straightful: 1)all displayed are layers, 2)WW call the layers' onDraw to gather and cache gl operations. The layer needs to transform the gl (move, rotate, ...) before it perform gl operations and restore the configuration of the gl passed in as a parameter.

I think the coordination is right, as you said (x,-y,-z).

The key is that jPCT's IThreadBuffer do not insert its gl operations into WW's queue before WW commit them to the display card. However the JFrame receives the image later.
So, can i inject the cached gl operations in IThreadBuffer to WW's gl queue by calling JOGLCanvas.display(null) method? Or world you please adjust that and open a direct-call method to do that.

iamfoolberg

After change the injectGL method, i think i see the box:)

I add an injectExternalGL method and change the injectGL in JOGLCanvas as following:

private GL externalGL = null;

/**
* inject the external GL
* @param gl null means no external GL
*/
public void injectExternalGL(GL gl){
externalGL = gl;
}

/**the last GL injected.*/
private GL lastGL = null;

private void injectGL() {
GL gl;
if(externalGL!=null){
gl = externalGL;
}else{
gl = GLContext.getCurrent().getGL();
}
if(lastGL==gl){
return;
}
Class<?>[] classes = new Class[] { org.lwjgl.opengl.GL11.class,
org.lwjgl.opengl.GL15.class, org.lwjgl.opengl.GL20.class,
org.lwjgl.opengl.Util.class,
org.lwjgl.opengl.ARBMultitexture.class,
org.lwjgl.opengl.EXTFramebufferObject.class,
org.lwjgl.opengl.ARBShaderObjects.class,
org.lwjgl.opengl.GLContext.class };
for (int i = 0; i < classes.length; i++) {
Class<?> clazz = classes[i];
try {
Field glf = clazz.getDeclaredField("gl");
glf.set(clazz, gl);
} catch (Exception e) {
Logger.log("Unable to inject GL context into the facade!",
Logger.ERROR);
}
}
}


Then, create a Util class in package com.threed.jpct to access the JOGLCanvas:

package com.threed.jpct;

import java.awt.Canvas;

import javax.media.opengl.GL;

public class Util {
public static void forceDraw(Canvas canvas){
JOGLCanvas jc = (JOGLCanvas)canvas;
jc.display(null);
}

public static void injectExternalGL(Canvas canvas, GL gl){
JOGLCanvas jc = (JOGLCanvas)canvas;
jc.injectExternalGL(gl);
}
}


The forceDraw method calls the "public void display(GLAutoDrawable tGLAutoDrawable)" to draw to gl (we injected by injectExternalGL).

Then i can see the box as the picture in attachment shows.

So, next questions are: 1. how can i clear the canvas with transparent color? 2. can i adjust the camera to see as far as possible?

iamfoolberg

I remove the buffer clear operation in the repaint method, now i can see the WW's other layers.
However, the map layer is affected, all map textures are virtically placed, as in attachment.

I think the texture "matrix" is modified and not restored.
So, how can i save the configuration of GL in beginDraw(DrawContext), and restore it in endDraw(DrawContext dc).

Hope this is the last BUG question:)


package org.aoe.det.ww.d3man.ww;

import java.awt.Canvas;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;

import org.aoe.det.ww.d3man.D3Man;
import org.gbzh.util.log.Log;
import org.gbzh.util.resource.Resource;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.Util;
import com.threed.jpct.World;

import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.render.DrawContext;

/**
* A jPCT based three model layer. In jPCT, positive x goes to the right,
* positive z goes INTO the screen and positive y goes DOWN. In worldwind,
* positive x goes to the right, positive z goes OUT the screen and positive
* goes UP. In worldwind,cartesian coordinates's point(0, 0, radius of the
* earth) has the longi/lati-tude position(0, 0, radius of the earth). longitude
* goes RIGHT to +180 and left to -180, latitude goes UP to +90 and down to -90.
*
* @author berg
*
*/
public class Jpct3DLayer extends AbstractLayer {
/** The world of jPCT. */
private World world;
/***/
private FrameBuffer buffer;
private GL2 lastGL;
private Canvas canvas;
private Object3D box;

public Jpct3DLayer() {
this.world = new World();
this.world.setAmbientLight(255, 255, 255);

TextureManager.getInstance().addTexture("box",
new Texture(Resource.getResource("data/red.jpg")));

box = Primitives.getBox(13f, 2f);

box.setTexture("box");
box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);
Position boxPos = Position.fromDegrees(0, 0, 13);
Position camPos = Position.fromDegrees(0, 0, 0);

setObject3DPosition(box, ww2jpct(boxPos));
this.world.getCamera().setPosition(ww2jpct(camPos));
this.world.getCamera().lookAt(ww2jpct(boxPos));

this.buffer = new FrameBuffer(800, 600,
FrameBuffer.SAMPLINGMODE_NORMAL);

canvas = buffer.enableGLCanvasRenderer();
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);

new Thread(){//rotate the box
@Override
public void run() {
while(true){
box.rotateZ(0.1f);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}

// puts opengl in the correct state for this layer
protected void beginDraw(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();

gl.glPushAttrib(GL2.GL_TEXTURE_BIT | GL2.GL_ENABLE_BIT
| GL2.GL_CURRENT_BIT | GL2.GL_TRANSFORM_BIT);

if (!dc.isPickingMode()) {
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
}

gl.glMatrixMode(javax.media.opengl.GL2.GL_MODELVIEW);
gl.glPushMatrix();

// inject gl if neccessary
if (this.lastGL != gl) {
Util.injectExternalGL(canvas, gl);
this.lastGL = gl;
}
}

// resets opengl state
protected void endDraw(DrawContext dc) {
GL2 gl = (GL2) dc.getGL();

gl.glMatrixMode(javax.media.opengl.GL2.GL_MODELVIEW);
gl.glPopMatrix();

gl.glPopAttrib();
}

/**
* convert WorldWind's Vec4 to jPCT's SimpleVector.
*
* @param x
* @param y
* @param z
* @return
*/
public static SimpleVector ww2jpct(double x, double y, double z) {
return new SimpleVector((float) x, (float) -y, (float) -z);
}

/**
* convert WorldWind's Vec4 to jPCT's SimpleVector.
*
* @param x
* @param y
* @param z
* @return
*/
public static SimpleVector ww2jpct(Vec4 vec) {
return new SimpleVector((float) vec.x, (float) -vec.y, (float) -vec.z);
}

/**
* move the object to the given position, not delta.
*
* @param obj
*            the object to me moved
* @param sv
*            the target position
*/
public static void setObject3DPosition(Object3D obj, SimpleVector sv) {
method: do {
if (sv == null || obj == null) {
Log.e("The input param sv or obj is null.");
break method;
}
SimpleVector cur = obj.getTranslation();
obj.translate(sv.calcSub(cur));
} while (false);
}
/**
* move the object to the given position, not delta.
* x,y,z is jPCT coordinate.
* @param obj
* @param x
* @param y
* @param z
*/
public static void setObject3DPosition(Object3D obj, float x, float y,
float z) {
method: do {
if (obj == null) {
Log.e("The input param obj is null.");
break method;
}
SimpleVector sv = new SimpleVector(x, y, z);
SimpleVector cur = obj.getTranslation();
obj.translate(sv.calcSub(cur));
} while (false);
}

public static Vec4 jpct2wwPoint(float x, float y, float z) {
return new Vec4(x, -y, -z);
}

public static Vec4 jpct2wwPoint(SimpleVector sv) {
Vec4 result = null;
method: do {
if (sv == null) {
Log.e("The input param sv is null.");
break method;
}
result = new Vec4(sv.x, -sv.y, -sv.z);
} while (false);
return result;
}

public static SimpleVector ww2jpct(Position position) {
SimpleVector result = null;
method: do {
if (position == null) {
Log.e("The input param position is null.");
break method;
}
Vec4 vec = D3Man.getInstance().position2Point(position);
result = new SimpleVector((float) vec.x, (float) -vec.y,
(float) -vec.z);
} while (false);
return result;
}

public static Position jpct2wwPosition(float x, float y, float z) {
return D3Man.getInstance().point2Position(x, -y, -z);
}

public static Position jpct2wwPosition(SimpleVector sv) {
Position result = null;
method: do {
if (sv == null) {
Log.e("The input param sv is null.");
break method;
}
result = D3Man.getInstance().point2Position(sv.x, -sv.y, -sv.z);
} while (false);
return result;
}

/**
* Called by WorldWind to refresh this layer.
*/
@Override
protected void doRender(DrawContext dc) {
this.beginDraw(dc);

// get the eye point of WW, to set the camera in jPCT
// so that jpct's camera go with ww's eye point
Vec4 eyeLoc = dc.getView().getEyePoint();
this.world.getCamera().setPosition(ww2jpct(eyeLoc));
this.world.getCamera().lookAt(new SimpleVector(0, 0, 0));

// save current gl settings before change it
dc.getView().pushReferenceCenter(dc, eyeLoc);

// jPCT draw its world with the given gl
this.repaint();

// force jPCT to draw on WW's gl.
Util.forceDraw(canvas);

    // restore last gl settings
dc.getView().popReferenceCenter(dc);
this.endDraw(dc);
}

/**
* force this layer to redraw components inside it.
*/
public void repaint() {
// buffer.clear(new Color(0.0f,0.0f,0.0f,1.0f));
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
canvas.repaint();
}
}