Jogl 2

Hi!



I suggested to port JMonkeyEngine 3 to JOGL 2, only a few classes will be impacted as they all are in src/jogl as far as I know and only a few refer directly to JOGL (JoglAbstractDisplay only needs some changes in the imports and to override the dispose method).



However, I have just read that “To move forward, something needs to be left behind; this time it”s OpenGL 1”. Would it be not trivial to get a partial support of OpenGL 1 with JMonkeyEngine 3?



Anyway I will find a way to test such a port on a recent machine but the lack of OpenGL 1 support won’t allow me to work with it any further.



Best regards.

Cool! About OpenGL 1, the shader code in jME3 depends on opengl here and there, you can simple shaders like ColoredTextured.j3md, they should work on OpenGL 1.0 afaik.

Cheers,

Normen

The non-existent support of OpenGL1 is really just a question of time. Since jME2 is still around for the lower requirement projects, and since jME3 is shader based, OpenGL1 just never made it to top priority. That doesn’t mean we would reject it if someone happened to contribute their work :slight_smile: We can’t guarantee it will make it into the core, but we’ve got good ways of giving important non-core projects more attention now, like including it as a plugin for jMonkeyPlatform, and making a dedicated group for it.



So as far as OpenGL1 goes, we’re absolutely welcome to it. As far as your necessary changes and general strategy goes though, I’ll leave that to the developers to evaluate.

I get this when I launch a Web Start demo of JMonkeyEngine 3 using JOGL:

Exception in thread “AWT-EventQueue-0” java.lang.UnsatisfiedLinkError: no gluegen-rt in java.library.path

at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)

at java.lang.Runtime.loadLibrary0(Runtime.java:823)

at java.lang.System.loadLibrary(System.java:1028)

at com.sun.gluegen.runtime.NativeLibLoader.loadLibraryInternal(NativeLibLoader.java:102)

at com.sun.gluegen.runtime.NativeLibLoader.access$000(NativeLibLoader.java:51)

at com.sun.gluegen.runtime.NativeLibLoader$1.run(NativeLibLoader.java:70)

at java.security.AccessController.doPrivileged(Native Method)

at com.sun.gluegen.runtime.NativeLibLoader.loadGlueGenRT(NativeLibLoader.java:68)

at com.sun.gluegen.runtime.NativeLibrary.ensureNativeLibLoaded(NativeLibrary.java:399)

at com.sun.gluegen.runtime.NativeLibrary.open(NativeLibrary.java:163)

at com.sun.gluegen.runtime.NativeLibrary.open(NativeLibrary.java:129)

at com.sun.opengl.impl.x11.DRIHack.begin(DRIHack.java:109)

at com.sun.opengl.impl.x11.X11GLDrawableFactory.(X11GLDrawableFactory.java:99)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:169)

at javax.media.opengl.GLDrawableFactory.getFactory(GLDrawableFactory.java:111)

at javax.media.opengl.GLCanvas.chooseGraphicsConfiguration(GLCanvas.java:520)

at javax.media.opengl.GLCanvas.(GLCanvas.java:131)

at javax.media.opengl.GLCanvas.(GLCanvas.java:90)

at com.jme3.system.jogl.JoglAbstractDisplay$1.(JoglAbstractDisplay.java:83)

at com.jme3.system.jogl.JoglAbstractDisplay.initGLCanvas(JoglAbstractDisplay.java:83)

at com.jme3.system.jogl.JoglDisplay.initInEDT(JoglDisplay.java:188)

at com.jme3.system.jogl.JoglDisplay.access$000(JoglDisplay.java:52)

at com.jme3.system.jogl.JoglDisplay$3.run(JoglDisplay.java:225)

at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)

at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)

at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)

at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)

at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)



I use a 32-bits Linux at home. It is strange because jME3-jogl-natives.jar contains libgluegen-rt.so.

JOGL is not working atm, we should remove that option, really.

It should work though. I haven’t touched the native extraction part so it’s really strange that it doesn’t work now.

Hi!



I reproduce this bug on another machine using Cent OS 5.3 but with a 64-bits JVM :frowning:

WEll I can start it with jogl, but wel there is really no sense to do it ^^

EmpirePhoenix said:
WEll I can start it with jogl, but wel there is really no sense to do it ^^

What do you mean?

Well the current jogl rendere is not usable for anything right now, and is really instable in respect to materials ( as it just crashes when there is any material with a shader usually) (a error texture material would be a better solution , really)

EmpirePhoenix said:
Well the current jogl rendere is not usable for anything right now, and is really instable in respect to materials ( as it just crashes when there is any material with a shader usually) (a error texture material would be a better solution , really)

Ok I see that the JOGL renderer of JMonkeyEngine 3 follows the long tradition of JMonkeyEngine...

erlend_sh, where can I put the source code? I'm porting it right now...

[java]/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.jme3.renderer.jogl;

import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
import com.jme3.light.LightList;
import com.jme3.light.PointLight;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix4f;
import com.jme3.renderer.Caps;
import com.jme3.renderer.GLObjectManager;
import com.jme3.renderer.IDList;
import com.jme3.renderer.RenderContext;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.Statistics;
import com.jme3.scene.Mesh;
import com.jme3.scene.Mesh.Mode;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.shader.Shader;
import com.jme3.shader.Shader.ShaderSource;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapAxis;
import com.jme3.util.BufferUtils;
import com.jme3.util.IntMap;
import com.jme3.util.IntMap.Entry;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Collection;
import java.util.EnumSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;

public class JoglRenderer implements Renderer {

private static final Logger logger = Logger.getLogger(JoglRenderer.class.getName());

protected Statistics statistics = new Statistics();

protected Matrix4f worldMatrix = new Matrix4f();
protected Matrix4f viewMatrix = new Matrix4f();
protected Matrix4f projMatrix = new Matrix4f();
protected FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
protected IntBuffer ib1 = BufferUtils.createIntBuffer(1);
protected GL gl;

private RenderContext context = new RenderContext();
private GLObjectManager objManager = new GLObjectManager();

private EnumSet caps = EnumSet.noneOf(Caps.class);
private boolean powerOf2 = false;
private boolean hardwareMips = false;
private boolean vbo = false;

private int vpX, vpY, vpW, vpH;

public JoglRenderer(GL gl){
this.gl = gl;
}

public void setGL(GL gl){
this.gl = gl;
}

public Statistics getStatistics(){
return statistics;
}

public void initialize(){
logger.log(Level.INFO, "Vendor: {0}", gl.glGetString(GL.GL_VENDOR));
logger.log(Level.INFO, "Renderer: {0}", gl.glGetString(GL.GL_RENDERER));
logger.log(Level.INFO, "Version: {0}", gl.glGetString(GL.GL_VERSION));

applyRenderState(RenderState.DEFAULT);

powerOf2 = gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two");
hardwareMips = gl.isExtensionAvailable("GL_SGIS_generate_mipmap");
vbo = gl.isExtensionAvailable("GL_ARB_vertex_buffer_object");
}

public Collection getCaps() {
return caps;
}

public void setBackgroundColor(ColorRGBA color) {
gl.glClearColor(color.r, color.g, color.b, color.a);
}

public void cleanup(){
objManager.deleteAllObjects(this);
}

public void resetGLObjects(){
objManager.resetObjects();
}

public void clearBuffers(boolean color, boolean depth, boolean stencil) {
int bits = 0;
if (color) bits = GL.GL_COLOR_BUFFER_BIT;
if (depth) bits |= GL.GL_DEPTH_BUFFER_BIT;
if (stencil) bits |= GL.GL_STENCIL_BUFFER_BIT;
if (bits != 0) gl.glClear(bits);
}

public void applyRenderState(RenderState state){
if (state.isWireframe() && !context.wireframe){
gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE);
context.wireframe = true;
}else if (!state.isWireframe() && context.wireframe){
gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL);
context.wireframe = false;
}
if (state.isDepthTest() && !context.depthTestEnabled){
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
context.depthTestEnabled = true;
}else if (!state.isDepthTest() && context.depthTestEnabled){
gl.glDisable(GL.GL_DEPTH_TEST);
context.depthTestEnabled = false;
}
if (state.isAlphaTest() && !context.alphaTestEnabled){
gl.glEnable(GL2.GL_ALPHA_TEST);
gl.getGL2().glAlphaFunc(GL2.GL_GREATER, state.getAlphaFallOff());
context.alphaTestEnabled = true;
}else if (!state.isAlphaTest() && context.alphaTestEnabled){
gl.glDisable(GL2.GL_ALPHA_TEST);
context.alphaTestEnabled = false;
}
if (state.isDepthWrite() && !context.depthWriteEnabled){
gl.glDepthMask(true);
context.depthWriteEnabled = true;
}else if (!state.isDepthWrite() && context.depthWriteEnabled){
gl.glDepthMask(false);
context.depthWriteEnabled = false;
}
if (state.isColorWrite() && !context.colorWriteEnabled){
gl.glColorMask(true,true,true,true);
context.colorWriteEnabled = true;
}else if (!state.isColorWrite() && context.colorWriteEnabled){
gl.glColorMask(false,false,false,false);
context.colorWriteEnabled = false;
}
if (state.isPolyOffset()){
if (!context.polyOffsetEnabled){
gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
gl.glPolygonOffset(state.getPolyOffsetFactor(),
state.getPolyOffsetUnits());
context.polyOffsetEnabled = true;
context.polyOffsetFactor = state.getPolyOffsetFactor();
context.polyOffsetUnits = state.getPolyOffsetUnits();
}else{
if (state.getPolyOffsetFactor() != context.polyOffsetFactor
|| state.getPolyOffsetUnits() != context.polyOffsetUnits){
gl.glPolygonOffset(state.getPolyOffsetFactor(),
state.getPolyOffsetUnits());
context.polyOffsetFactor = state.getPolyOffsetFactor();
context.polyOffsetUnits = state.getPolyOffsetUnits();
}
}
}else{
if (context.polyOffsetEnabled){
gl.glDisable(GL.GL_POLYGON_OFFSET_FILL);
context.polyOffsetEnabled = false;
context.polyOffsetFactor = 0;
context.polyOffsetUnits = 0;
}
}
if (state.getFaceCullMode() != context.cullMode){
if (state.getFaceCullMode() == RenderState.FaceCullMode.Off)
gl.glDisable(GL.GL_CULL_FACE);
else
gl.glEnable(GL.GL_CULL_FACE);

switch (state.getFaceCullMode()){
case Off:
break;
case Back:
gl.glCullFace(GL.GL_BACK);
break;
case Front:
gl.glCullFace(GL.GL_FRONT);
break;
case FrontAndBack:
gl.glCullFace(GL.GL_FRONT_AND_BACK);
break;
default:
throw new UnsupportedOperationException("Unrecognized face cull mode: "+
state.getFaceCullMode());
}

context.cullMode = state.getFaceCullMode();
}

if (state.getBlendMode() != context.blendMode){
if (state.getBlendMode() == RenderState.BlendMode.Off)
gl.glDisable(GL.GL_BLEND);
else
gl.glEnable(GL.GL_BLEND);

switch (state.getBlendMode()){
case Off:
break;
case Additive:
gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE);
break;
case AlphaAdditive:
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
break;
case Alpha:
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
break;
case Color:
gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR);
break;
case PremultAlpha:
gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);
break;
case Modulate:
gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_ZERO);
break;
case ModulateX2:
gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_SRC_COLOR);
break;
default:
throw new UnsupportedOperationException("Unrecognized blend mode: "+
state.getBlendMode());
}

context.blendMode = state.getBlendMode();
}
}

public void onFrame() {
objManager.deleteUnused(this);
}

public void setDepthRange(float start, float end) {
gl.glDepthRange(start, end);
}

public void setViewPort(int x, int y, int width, int height){
gl.glViewport(x, y, width, height);
vpX = x;
vpY = y;
vpW = width;
vpH = height;
}

public void setClipRect(int x, int y, int width, int height){
if (!context.clipRectEnabled){
gl.glEnable(GL.GL_SCISSOR_TEST);
context.clipRectEnabled = true;
}
gl.glScissor(x, y, width, height);
}

public void clearClipRect(){
if (context.clipRectEnabled){
gl.glDisable(GL.GL_SCISSOR_TEST);
context.clipRectEnabled = false;
}
}

private FloatBuffer storeMatrix(Matrix4f matrix, FloatBuffer store){
store.rewind();
matrix.fillFloatBuffer(store,true);
store.rewind();
return store;
}

public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix){
this.viewMatrix.set(viewMatrix);
this.projMatrix.set(projMatrix);

if (context.matrixMode != GL2.GL_PROJECTION){
gl.getGL2().glMatrixMode(GL2.GL_PROJECTION);
context.matrixMode = GL2.GL_PROJECTION;
}

gl.getGL2().glLoadMatrixf(storeMatrix(projMatrix,fb16));
}

public void setWorldMatrix(Matrix4f worldMatrix) {
this.worldMatrix.set(worldMatrix);

if (context.matrixMode != GL2.GL_MODELVIEW){
gl.getGL2().glMatrixMode(GL2.GL_MODELVIEW);
context.matrixMode = GL2.GL_MODELVIEW;
}

gl.getGL2().glLoadMatrixf(storeMatrix(viewMatrix,fb16));
gl.getGL2().glMultMatrixf(storeMatrix(worldMatrix,fb16));
}

public void setLighting(LightList list) {
if (list == null || list.size() == 0) {
// turn off lighting
gl.glDisable(GL2.GL_LIGHTING);
return;
}

gl.glEnable(GL2.GL_LIGHTING);
gl.getGL2().glShadeModel(GL2.GL_SMOOTH);

float[] temp = new float[4];

// reset model view to specify
// light positions in world space
// instead of model space
// gl.glPushMatrix();
// gl.glLoadIdentity();

for (int i = 0; i < list.size()+1; i++){

int lightId = GL2.GL_LIGHT0 + i;

if (list.size() <= i){
// goes beyond the num lights we need
// disable it
gl.glDisable(lightId);
break;
}

Light l = list.get(i);

if (!l.isEnabled()){
gl.glDisable(lightId);
continue;
}

ColorRGBA color = l.getColor();
color.toArray(temp);

gl.glEnable(lightId);
gl.getGL2().glLightfv(lightId, GL2.GL_DIFFUSE, temp, 0);
gl.getGL2().glLightfv(lightId, GL2.GL_SPECULAR, temp, 0);

ColorRGBA.Black.toArray(temp);
gl.getGL2().glLightfv(lightId, GL2.GL_AMBIENT, temp, 0);

switch (l.getType()){
case Directional:
DirectionalLight dl = (DirectionalLight) l;
dl.getDirection().toArray(temp);
temp[3] = 0f; // marks to GL its a directional light
gl.getGL2().glLightfv(lightId, GL2.GL_POSITION, temp, 0);
break;
case Point:
PointLight pl = (PointLight) l;
pl.getPosition().toArray(temp);
temp[3] = 1f; // marks to GL its a point light
gl.getGL2().glLightfv(lightId, GL2.GL_POSITION, temp, 0);
break;
}

}

// restore modelview to original value
// gl.glPopMatrix();
}

public void deleteShaderSource(ShaderSource source) {
}

public void setShader(Shader shader) {
}

public void deleteShader(Shader shader) {
}

public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
}

public void setFrameBuffer(FrameBuffer fb) {
}

public void deleteFrameBuffer(FrameBuffer fb) {
}

public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf){
if (fb != null)
return;

gl.glReadPixels(vpX, vpY, vpW, vpH, GL2.GL_BGRA, GL.GL_UNSIGNED_BYTE, byteBuf);
}

private int convertTextureType(Texture.Type type){
switch (type){
case TwoDimensional:
return GL.GL_TEXTURE_2D;
case TwoDimensionalArray:
return GL.GL_TEXTURE_2D_ARRAY;
case ThreeDimensional:
return GL2.GL_TEXTURE_3D;
case CubeMap:
return GL.GL_TEXTURE_CUBE_MAP;
default:
throw new UnsupportedOperationException("Unknown texture type: "+type);
}
}

private int convertMagFilter(Texture.MagFilter filter){
switch (filter){
case Bilinear:
return GL.GL_LINEAR;
case Nearest:
return GL.GL_NEAREST;
default:
throw new UnsupportedOperationException("Unknown mag filter: "+filter);
}
}

private int convertMinFilter(Texture.MinFilter filter){
switch (filter){
case Trilinear:
return GL.GL_LINEAR_MIPMAP_LINEAR;
case BilinearNearestMipMap:
return GL.GL_LINEAR_MIPMAP_NEAREST;
case NearestLinearMipMap:
return GL.GL_NEAREST_MIPMAP_LINEAR;
case NearestNearestMipMap:
return GL.GL_NEAREST_MIPMAP_NEAREST;
case BilinearNoMipMaps:
return GL.GL_LINEAR;
case NearestNoMipMaps:
return GL.GL_NEAREST;
default:
throw new UnsupportedOperationException("Unknown min filter: "+filter);
}
}

private int convertWrapMode(Texture.WrapMode mode){
switch (mode){
case BorderClamp:
return GL2.GL_CLAMP_TO_BORDER;
case Clamp:
return GL2.GL_CLAMP;
case EdgeClamp:
return GL.GL_CLAMP_TO_EDGE;
case Repeat:
return GL.GL_REPEAT;
case MirroredRepeat:
return GL.GL_MIRRORED_REPEAT;
default:
throw new UnsupportedOperationException("Unknown wrap mode: "+mode);
}
}

public void updateTextureData(Texture tex) {
int texId = tex.getId();
if (texId == -1){
// create texture
gl.glGenTextures(1, ib1);
texId = ib1.get(0);
tex.setId(texId);
objManager.registerForCleanup(tex);
}

// bind texture
int target = convertTextureType(tex.getType());
if (context.boundTextures[0] != tex){
if (context.boundTextureUnit != 0){
gl.glActiveTexture(GL.GL_TEXTURE0);
context.boundTextureUnit = 0;
}

gl.glBindTexture(target, texId);
context.boundTextures[0] = tex;
}

// filter things
int minFilter = convertMinFilter(tex.getMinFilter());
int magFilter = convertMagFilter(tex.getMagFilter());
gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, minFilter);
gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, magFilter);

// repeat modes
switch (tex.getType()){
case ThreeDimensional:
case CubeMap:
gl.glTexParameteri(target, GL2.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R)));
case TwoDimensional:
gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T)));
// fall down here is intentional..
// case OneDimensional:
gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S)));
break;
default:
throw new UnsupportedOperationException("Unknown texture type: "+tex.getType());
}

Image img = tex.getImage();
if (img != null){
boolean generateMips = false;
if (!img.hasMipmaps() && tex.getMinFilter().usesMipMapLevels()){
// No pregenerated mips available,
// generate from base level if required
if (hardwareMips){
gl.glTexParameteri(target, GL2.GL_GENERATE_MIPMAP, GL.GL_TRUE);
}else{
generateMips = true;
}
}

TextureUtil.uploadTexture(gl, img, tex.getImageDataIndex(), generateMips, powerOf2);
}

tex.clearUpdateNeeded();
}

private void checkTexturingUsed(){
IDList textureList = context.textureIndexList;
// old mesh used texturing, new mesh doesn't use it
// should actually go through entire oldLen and
// disable texturing for each unit.. but that's for later.
if (textureList.oldLen > 0 && textureList.newLen == 0){
gl.glDisable(GL.GL_TEXTURE_2D);
}
}

public void setTexture(int unit, Texture tex) {
if (tex.isUpdateNeeded())
updateTextureData(tex);

int texId = tex.getId();
assert texId != -1;

Texture[] textures = context.boundTextures;

int type = convertTextureType(tex.getType());
if (!context.textureIndexList.moveToNew(unit)){
if (context.boundTextureUnit != unit){
gl.glActiveTexture(GL.GL_TEXTURE0 + unit);
context.boundTextureUnit = unit;
}

gl.glEnable(type);
}

if (textures[unit] != tex){
if (context.boundTextureUnit != unit){
gl.glActiveTexture(GL.GL_TEXTURE0 + unit);
context.boundTextureUnit = unit;
}

gl.glBindTexture(type, texId);
textures[unit] = tex;
}
}

public void clearTextureUnits() {
IDList textureList = context.textureIndexList;
Texture[] textures = context.boundTextures;
for (int i = 0; i < textureList.oldLen; i++){
int idx = textureList.oldList;

if (context.boundTextureUnit != idx){
gl.glActiveTexture(GL.GL_TEXTURE0 + idx);
context.boundTextureUnit = idx;
}
gl.glDisable(convertTextureType(textures[idx].getType()));
textures[idx] = null;
}
context.textureIndexList.copyNewToOld();
}

public void deleteTexture(Texture tex) {
int texId = tex.getId();
if (texId != -1){
ib1.put(0, texId);
ib1.position(0).limit(1);
gl.glDeleteTextures(1, ib1);
tex.resetObject();
}
}

private int convertUsage(Usage usage){
switch (usage){
case Static:
return GL.GL_STATIC_DRAW;
case Dynamic:
return GL.GL_DYNAMIC_DRAW;
case Stream:
return GL2.GL_STREAM_DRAW;
default:
throw new RuntimeException("Unknown usage type: "+usage);
}
}

public void updateBufferData(VertexBuffer vb) {
int bufId = vb.getId();
if (bufId == -1){
// create buffer
gl.glGenBuffers(1, ib1);
bufId = ib1.get(0);
vb.setId(bufId);
objManager.registerForCleanup(vb);
}

int target;
if (vb.getBufferType() == VertexBuffer.Type.Index){
target = GL.GL_ELEMENT_ARRAY_BUFFER;
if (context.boundElementArrayVBO != bufId){
gl.glBindBuffer(target, bufId);
context.boundElementArrayVBO = bufId;
}
}else{
target = GL.GL_ARRAY_BUFFER;
if (context.boundArrayVBO != bufId){
gl.glBindBuffer(target, bufId);
context.boundArrayVBO = bufId;
}
}

int usage = convertUsage(vb.getUsage());
Buffer data = vb.getData();
data.rewind();

gl.glBufferData(target,
data.capacity() * vb.getFormat().getComponentSize(),
data,
usage);

vb.clearUpdateNeeded();
}

public void deleteBuffer(VertexBuffer vb) {
int bufId = vb.getId();
if (bufId != -1){
// delete buffer
ib1.put(0, bufId);
ib1.position(0).limit(1);
gl.glDeleteBuffers(1, ib1);
vb.resetObject();
}
}

private int convertArrayType(VertexBuffer.Type type){
switch (type){
case Position:
return GL2.GL_VERTEX_ARRAY;
case Normal:
return GL2.GL_NORMAL_ARRAY;
case TexCoord:
return GL2.GL_TEXTURE_COORD_ARRAY;
case Color:
return GL2.GL_COLOR_ARRAY;
default:
return -1; // unsupported
}
}

private int convertVertexFormat(VertexBuffer.Format fmt){
switch (fmt){
case Byte:
return GL.GL_BYTE;
case Double:
return GL2.GL_DOUBLE;
case Float:
return GL.GL_FLOAT;
case Half:
return GL.GL_HALF_FLOAT;
case Int:
return GL2.GL_INT;
case Short:
return GL.GL_SHORT;
case UnsignedByte:
return GL.GL_UNSIGNED_BYTE;
case UnsignedInt:
return GL2.GL_UNSIGNED_INT;
case UnsignedShort:
return GL.GL_UNSIGNED_SHORT;
default:
throw new UnsupportedOperationException("Unrecognized vertex format: "+fmt);
}
}

private int convertElementMode(Mesh.Mode mode){
switch (mode){
case Points:
return GL.GL_POINTS;
case Lines:
return GL.GL_LINES;
case LineLoop:
return GL.GL_LINE_LOOP;
case LineStrip:
return GL.GL_LINE_STRIP;
case Triangles:
return GL.GL_TRIANGLES;
case TriangleFan:
return GL.GL_TRIANGLE_FAN;
case TriangleStrip:
return GL.GL_TRIANGLE_STRIP;
default:
throw new UnsupportedOperationException("Unrecognized mesh mode: "+mode);
}
}

private void setVertexAttribVBO(VertexBuffer vb, VertexBuffer idb){
int arrayType = convertArrayType(vb.getBufferType());
if (arrayType == -1)
return; // unsupported

if (vb.isUpdateNeeded() && idb == null)
updateBufferData(vb);

int bufId = idb != null ? idb.getId() : vb.getId();
if (context.boundArrayVBO != bufId){
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, bufId);
context.boundArrayVBO = bufId;
}

gl.getGL2().glEnableClientState(arrayType);
context.boundAttribs[vb.getBufferType().ordinal()] = vb;

if (vb.getBufferType() == Type.Normal){
// normalize if requested
if (vb.isNormalized() && !context.normalizeEnabled){
gl.glEnable(GL2.GL_NORMALIZE);
context.normalizeEnabled = true;
}else if (!vb.isNormalized() && context.normalizeEnabled){
gl.glDisable(GL2.GL_NORMALIZE);
context.normalizeEnabled = false;
}
}

int comps = vb.getNumComponents();
int type = convertVertexFormat(vb.getFormat());

switch (vb.getBufferType()){
case Position:
gl.getGL2().glVertexPointer(comps, type, vb.getStride(), vb.getOffset());
break;
case Normal:
gl.getGL2().glNormalPointer(type, vb.getStride(), vb.getOffset());
break;
case Color:
gl.getGL2().glColorPointer(comps, type, vb.getStride(), vb.getOffset());
break;
case TexCoord:
gl.getGL2().glTexCoordPointer(comps, type, vb.getStride(), vb.getOffset());
break;
}
}

private void drawTriangleListVBO(VertexBuffer indexBuf, Mesh mesh, int count){
if (indexBuf.getBufferType() != VertexBuffer.Type.Index)
throw new IllegalArgumentException("Only index buffers are allowed as triangle lists.");

if (indexBuf.isUpdateNeeded())
updateBufferData(indexBuf);

int bufId = indexBuf.getId();
assert bufId != -1;

if (context.boundElementArrayVBO != bufId){
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, bufId);
context.boundElementArrayVBO = bufId;
}

if (mesh.getMode() == Mode.Hybrid){
int[] modeStart = mesh.getModeStart();
int[] elementLengths = mesh.getElementLengths();

int elMode = convertElementMode(Mode.Triangles);
int fmt = convertVertexFormat(indexBuf.getFormat());
int elSize = indexBuf.getFormat().getComponentSize();
// int listStart = modeStart[0];
int stripStart = modeStart[1];
int fanStart = modeStart[2];
int curOffset = 0;
for (int i = 0; i < elementLengths.length; i++){
if (i == stripStart){
elMode = convertElementMode(Mode.TriangleStrip);
}else if (i == fanStart){
elMode = convertElementMode(Mode.TriangleStrip);
}
int elementLength = elementLengths;
gl.glDrawElements(elMode,
elementLength,
fmt,
curOffset);
curOffset += elementLength * elSize;
}
}else{
gl.glDrawElements(convertElementMode(mesh.getMode()),
indexBuf.getData().capacity(),
convertVertexFormat(indexBuf.getFormat()),
0);
}
}

public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) {
int arrayType = convertArrayType(vb.getBufferType());
if (arrayType == -1)
return; // unsupported

gl.getGL2().glEnableClientState(arrayType);
context.boundAttribs[vb.getBufferType().ordinal()] = vb;

if (vb.getBufferType() == Type.Normal){
// normalize if requested
if (vb.isNormalized() && !context.normalizeEnabled){
gl.glEnable(GL2.GL_NORMALIZE);
context.normalizeEnabled = true;
}else if (!vb.isNormalized() && context.normalizeEnabled){
gl.glDisable(GL2.GL_NORMALIZE);
context.normalizeEnabled = false;
}
}

// NOTE: Use data from interleaved buffer if specified
Buffer data = idb != null ? idb.getData() : vb.getData();
int comps = vb.getNumComponents();
int type = convertVertexFormat(vb.getFormat());
data.clear();
data.position(vb.getOffset());

switch (vb.getBufferType()){
case Position:
gl.getGL2().glVertexPointer(comps, type, vb.getStride(), data);
break;
case Normal:
gl.getGL2().glNormalPointer(type, vb.getStride(), data);
break;
case Color:
gl.getGL2().glColorPointer(comps, type, vb.getStride(), data);
break;
case TexCoord:
gl.getGL2().glTexCoordPointer(comps, type, vb.getStride(), data);
break;
}
}

public void setVertexAttrib(VertexBuffer vb){
setVertexAttrib(vb, null);
}

public void clearVertexAttribs() {
for (int i = 0; i < 16; i++){
VertexBuffer vb = context.boundAttribs;
if (vb != null){
int arrayType = convertArrayType(vb.getBufferType());
gl.getGL2().glDisableClientState(arrayType);
context.boundAttribs[vb.getBufferType().ordinal()] = null;
}
}
}

public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) {
Mesh.Mode mode = mesh.getMode();

Buffer indexData = indexBuf.getData();
indexData.clear();
if (mesh.getMode() == Mode.Hybrid){
int[] modeStart = mesh.getModeStart();
int[] elementLengths = mesh.getElementLengths();

int elMode = convertElementMode(Mode.Triangles);
int fmt = convertVertexFormat(indexBuf.getFormat());
// int elSize = indexBuf.getFormat().getComponentSize();
// int listStart = modeStart[0];
int stripStart = modeStart[1];
int fanStart = modeStart[2];
int curOffset = 0;
for (int i = 0; i < elementLengths.length; i++){
if (i == stripStart){
elMode = convertElementMode(Mode.TriangleStrip);
}else if (i == fanStart){
elMode = convertElementMode(Mode.TriangleStrip);
}
int elementLength = elementLengths;
indexData.position(curOffset);
gl.glDrawElements(elMode,
elementLength,
fmt,
indexData);
curOffset += elementLength;
}
}else{
gl.glDrawElements(convertElementMode(mode),
indexData.capacity(),
convertVertexFormat(indexBuf.getFormat()),
indexData);
}
}

private void renderMeshDefault(Mesh mesh, int lod, int count) {
VertexBuffer indices = null;
VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
IntMap buffers = mesh.getBuffers();
if (mesh.getNumLodLevels() > 0){
indices = mesh.getLodLevel(lod);
}else{
indices = buffers.get(Type.Index.ordinal());
}
for (Entry entry : buffers){
VertexBuffer vb = entry.getValue();

if (vb.getBufferType() == Type.InterleavedData
|| vb.getUsage() == Usage.CpuOnly) // ignore cpu-only buffers
continue;

if (vb.getBufferType() == Type.Index){
indices = vb;
}else{
if (vb.getStride() == 0){
// not interleaved
setVertexAttrib(vb);
}else{
// interleaved
setVertexAttrib(vb, interleavedData);
}
}
}

if (indices != null){
drawTriangleList(indices, mesh, count);
}else{
gl.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
}
clearVertexAttribs();
clearTextureUnits();
}

private void renderMeshVBO(Mesh mesh, int lod, int count){
VertexBuffer indices = null;
VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
if (interleavedData != null && interleavedData.isUpdateNeeded()){
updateBufferData(interleavedData);
}
IntMap buffers = mesh.getBuffers();
if (mesh.getNumLodLevels() > 0){
indices = mesh.getLodLevel(lod);
}else{
indices = buffers.get(Type.Index.ordinal());
}
for (Entry entry : buffers){
VertexBuffer vb = entry.getValue();

if (vb.getBufferType() == Type.InterleavedData
|| vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
|| vb.getBufferType() == Type.Index)
continue;

if (vb.getStride() == 0){
// not interleaved
setVertexAttribVBO(vb, null);
}else{
// interleaved
setVertexAttribVBO(vb, interleavedData);
}
}

if (indices != null){
drawTriangleListVBO(indices, mesh, count);
}else{
gl.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
}
clearVertexAttribs();
clearTextureUnits();
}

private void updateDisplayList(Mesh mesh){
if (mesh.getId() != -1){
// delete list first
gl.getGL2().glDeleteLists(mesh.getId(), mesh.getId());
mesh.setId(-1);
}

// create new display list
// first set state to NULL
applyRenderState(RenderState.NULL);

// disable lighting
setLighting(null);

int id = gl.getGL2().glGenLists(1);
mesh.setId(id);
gl.getGL2().glNewList(id, GL2.GL_COMPILE);
renderMeshDefault(mesh, 0, 1);
gl.getGL2().glEndList();
}

private void renderMeshDisplayList(Mesh mesh){
if (mesh.getId() == -1){
updateDisplayList(mesh);
}
gl.getGL2().glCallList(mesh.getId());
}

public void renderMesh(Mesh mesh, int lod, int count){
if (context.pointSize != mesh.getPointSize()){
gl.getGL2().glPointSize(mesh.getPointSize());
context.pointSize = mesh.getPointSize();
}
if (context.lineWidth != mesh.getLineWidth()){
gl.glLineWidth(mesh.getLineWidth());
context.lineWidth = mesh.getLineWidth();
}

checkTexturingUsed();

if (vbo){
renderMeshVBO(mesh, lod, count);
}else{
boolean dynamic = false;
if (mesh.getNumLodLevels() == 0){
IntMap bufs = mesh.getBuffers();
for (Entry entry : bufs){
if (entry.getValue().getUsage() != VertexBuffer.Usage.Static){
dynamic = true;
break;
}
}
}else{
dynamic = true;
}

if (!dynamic){
// dealing with a static object, generate display list
renderMeshDisplayList(mesh);
}else{
renderMeshDefault(mesh, lod, count);
}
}
}

}
[/java]

[java]/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.jme3.renderer.jogl;

import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import java.nio.ByteBuffer;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;

public class TextureUtil {

public static int convertTextureFormat(Format fmt){
switch (fmt){
case Alpha16:
case Alpha8:
return GL.GL_ALPHA;
case Luminance8Alpha8:
case Luminance16Alpha16:
return GL.GL_LUMINANCE_ALPHA;
case Luminance8:
case Luminance16:
return GL.GL_LUMINANCE;
case RGB10:
case RGB16:
case BGR8:
case RGB8:
case RGB565:
return GL.GL_RGB;
case RGB5A1:
case RGBA16:
case RGBA8:
return GL.GL_RGBA;
default:
throw new UnsupportedOperationException("Unrecognized format: "+fmt);
}
}

public static void uploadTexture(GL gl,
Image img,
int index,
boolean generateMips,
boolean powerOf2){

Image.Format fmt = img.getFormat();
ByteBuffer data;
if (index >= 0 || img.getData() != null && img.getData().size() > 0){
data = img.getData(index);
}else{
data = null;
}

int width = img.getWidth();
int height = img.getHeight();
// int depth = img.getDepth();

boolean compress = false;
int format = -1;
int internalFormat = -1;
int dataType = -1;

switch (fmt){
case Alpha16:
format = GL.GL_ALPHA;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_ALPHA16;
break;
case Alpha8:
format = GL.GL_ALPHA;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_ALPHA8;
break;
case Luminance8:
format = GL.GL_LUMINANCE;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_LUMINANCE8;
break;
case Luminance8Alpha8:
format = GL.GL_LUMINANCE_ALPHA;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_LUMINANCE8_ALPHA8;
break;
case Luminance16Alpha16:
format = GL.GL_LUMINANCE_ALPHA;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_LUMINANCE16_ALPHA16;
break;
case Luminance16:
format = GL.GL_LUMINANCE;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_LUMINANCE16;
break;
case RGB565:
format = GL.GL_RGB;
dataType = GL.GL_UNSIGNED_SHORT_5_6_5;
internalFormat = GL.GL_RGB8;
break;
case ARGB4444:
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_SHORT_4_4_4_4;
internalFormat = GL.GL_RGBA4;
break;
case RGB10:
format = GL.GL_RGB;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_RGB10;
break;
case RGB16:
format = GL.GL_RGB;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_RGB16;
break;
case RGB5A1:
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_SHORT_5_5_5_1;
internalFormat = GL.GL_RGB5_A1;
break;
case RGB8:
format = GL.GL_RGB;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL.GL_RGB8;
break;
case BGR8:
format = GL2.GL_BGR;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL.GL_RGB8;
break;
case RGBA16:
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL2.GL_RGBA16;
break;
case RGBA8:
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_BYTE;
internalFormat = GL.GL_RGBA8;
break;
case DXT1:
compress = true;
internalFormat = GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
format = GL.GL_RGB;
dataType = GL.GL_UNSIGNED_BYTE;
break;
case DXT1A:
compress = true;
internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_BYTE;
break;
case DXT3:
compress = true;
internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_BYTE;
break;
case DXT5:
compress = true;
internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
format = GL.GL_RGBA;
dataType = GL.GL_UNSIGNED_BYTE;
break;
default:
throw new UnsupportedOperationException("Unrecognized format: "+fmt);
}

if (data != null)
gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);

int[] mipSizes = img.getMipMapSizes();
int pos = 0;
if (mipSizes == null){
if (data != null)
mipSizes = new int[]{ data.capacity() };
else
mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 };
}

for (int i = 0; i < mipSizes.length; i++){
int mipWidth = Math.max(1, width >> i);
int mipHeight = Math.max(1, height >> i);
// int mipDepth = Math.max(1, depth >> i);

if (data != null){
data.position(pos);
data.limit(pos + mipSizes);
}

if (compress && data != null){
gl.glCompressedTexImage2D(GL.GL_TEXTURE_2D,
i,
internalFormat,
mipWidth,
mipHeight,
0,
data.remaining(),
data);
}else{
gl.glTexImage2D(GL.GL_TEXTURE_2D,
i,
internalFormat,
mipWidth,
mipHeight,
0,
format,
dataType,
data);
}

pos += mipSizes;
}
}

}
[/java]

[java]/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.jme3.system.jogl;

import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.awt.AwtKeyInput;
import com.jme3.input.awt.AwtMouseInput;
import com.jme3.renderer.jogl.JoglRenderer;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.AnimatorBase;
import com.jogamp.opengl.util.FPSAnimator;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;

public abstract class JoglAbstractDisplay extends JoglContext implements GLEventListener {

private static final Logger logger = Logger.getLogger(JoglAbstractDisplay.class.getName());

protected GraphicsDevice device;
protected GLCanvas canvas;
protected AnimatorBase animator;
protected AtomicBoolean active = new AtomicBoolean(false);

protected boolean wasActive = false;
protected int frameRate;
protected boolean useAwt = true;
protected AtomicBoolean autoFlush = new AtomicBoolean(true);
protected boolean wasAnimating = false;

static{
//FIXME: should be called as early as possible before any GUI task
GLProfile.initSingleton();
}

protected void initGLCanvas(){
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();

GLCapabilities caps = new GLCapabilities(GLProfile.getDefault());
caps.setHardwareAccelerated(true);
caps.setDoubleBuffered(true);
caps.setStencilBits(settings.getStencilBits());
caps.setDepthBits(settings.getDepthBits());

if (settings.getSamples() > 1){
caps.setSampleBuffers(true);
caps.setNumSamples(settings.getSamples());
}

canvas = new GLCanvas(caps){
@Override
public void addNotify(){
super.addNotify();
onCanvasAdded();
}
@Override
public void removeNotify(){
onCanvasRemoved();
super.removeNotify();
}
};
if (settings.isVSync()){
canvas.getGL().setSwapInterval(1);
}
canvas.setFocusable(true);
canvas.setIgnoreRepaint(true);
canvas.addGLEventListener(this);

GL gl = canvas.getGL();
// if (false){
// trace mode
// jME already uses err stream, use out instead
// gl = new TraceGL(gl, System.out);
// }else if (false){
// debug mode
// gl = new DebugGL(gl);
// }else{
// production mode
// }
renderer = new JoglRenderer(gl);
}

protected void startGLCanvas(){
if (frameRate > 0){
animator = new FPSAnimator(canvas, frameRate);
//((FPSAnimator)animator).setRunAsFastAsPossible(true);
}else{
animator = new Animator(canvas);
((Animator)animator).setRunAsFastAsPossible(true);
}

animator.start();
wasAnimating = true;
}

protected void onCanvasAdded(){
}

protected void onCanvasRemoved(){
}

@Override
public KeyInput getKeyInput(){
return new AwtKeyInput(canvas);
}

@Override
public MouseInput getMouseInput(){
return new AwtMouseInput(canvas);
}

public void setAutoFlushFrames(boolean enabled){
autoFlush.set(enabled);
}

/**
* Callback.
*/
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
listener.reshape(width, height);
}

/**
* Callback.
*/
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
}

/**
* Callback
*/
public void dispose(GLAutoDrawable drawable){

}
}
[/java]

[java]/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.jme3.system.jogl;

import com.jme3.system.JmeCanvasContext;
import java.awt.Canvas;
import java.util.logging.Logger;
import javax.media.opengl.GLAutoDrawable;

public class JoglCanvas extends JoglAbstractDisplay implements JmeCanvasContext {

private static final Logger logger = Logger.getLogger(JoglCanvas.class.getName());
private int width, height;

public JoglCanvas(){
super();
initGLCanvas();
}

public Type getType() {
return Type.Canvas;
}

public void setTitle(String title) {
}

public void restart() {
}

public void create(boolean waitFor){
if (waitFor)
waitFor(true);
}

public void destroy(boolean waitFor){
if (waitFor)
waitFor(false);
}

@Override
protected void onCanvasRemoved(){
super.onCanvasRemoved();
created.set(false);
waitFor(false);
}

@Override
protected void onCanvasAdded(){
startGLCanvas();
}

public void init(GLAutoDrawable drawable) {
canvas.requestFocus();

super.internalCreate();
logger.info("Display created.");

renderer.initialize();
listener.initialize();
}

public void display(GLAutoDrawable glad) {
if (!created.get() && renderer != null){
listener.destroy();
logger.info("Canvas destroyed.");
super.internalDestroy();
return;
}

if (width != canvas.getWidth() || height != canvas.getHeight()){
width = canvas.getWidth();
height = canvas.getHeight();
if (listener != null)
listener.reshape(width, height);
}

boolean flush = autoFlush.get();
if (flush && !wasAnimating){
animator.start();
wasAnimating = true;
}else if (!flush && wasAnimating){
animator.stop();
wasAnimating = false;
}

listener.update();
renderer.onFrame();

}

public Canvas getCanvas() {
return canvas;
}

@Override
public void dispose(GLAutoDrawable arg0) {
}

}
[/java]

[java]/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.jme3.system.jogl;

import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.awt.AwtKeyInput;
import com.jme3.input.awt.AwtMouseInput;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.jogl.JoglRenderer;
import com.jme3.system.AppSettings;
import com.jme3.system.SystemListener;
import com.jme3.system.JmeContext;
import com.jme3.system.NanoTimer;
import com.jme3.system.Timer;
import java.util.concurrent.atomic.AtomicBoolean;

public abstract class JoglContext implements JmeContext {

protected AtomicBoolean created = new AtomicBoolean(false);
protected final Object createdLock = new Object();

protected AppSettings settings = new AppSettings(true);
protected JoglRenderer renderer;
protected Timer timer;
protected SystemListener listener;

protected AwtKeyInput keyInput;
protected AwtMouseInput mouseInput;

public void setSystemListener(SystemListener listener){
this.listener = listener;
}

public void setSettings(AppSettings settings) {
this.settings.copyFrom(settings);
}

public AppSettings getSettings() {
return settings;
}

public Renderer getRenderer() {
return renderer;
}

public MouseInput getMouseInput() {
return mouseInput;
}

public KeyInput getKeyInput() {
return keyInput;
}

public JoyInput getJoyInput() {
return null;
}

public Timer getTimer() {
return timer;
}

public boolean isCreated() {
return created.get();
}

public void create(){
create(false);
}

public void destroy(){
destroy(false);
}

protected void waitFor(boolean createdVal){
synchronized (createdLock){
while (created.get() != createdVal){
try {
createdLock.wait();
} catch (InterruptedException ex) {
}
}
}
}

public void internalCreate() {
timer = new NanoTimer();
synchronized (createdLock){
created.set(true);
createdLock.notifyAll();
}
// renderer initialization must happen in subclass.
}

protected void internalDestroy() {
renderer = null;
timer = null;

synchronized (createdLock){
created.set(false);
createdLock.notifyAll();
}
}

}
[/java]

oh cool :wink: I will help with testing , with my intelonbaord netbook if that helps ( as it only supports opengl1.0) and then I coul play around a bit on it :slight_smile:

[java]/*

  • Copyright © 2009-2010 jMonkeyEngine
  • All rights reserved.

    *
  • Redistribution and use in source and binary forms, with or without
  • modification, are permitted provided that the following conditions are
  • met:

    *
    • Redistributions of source code must retain the above copyright
  • notice, this list of conditions and the following disclaimer.

    *
    • Redistributions in binary form must reproduce the above copyright
  • notice, this list of conditions and the following disclaimer in the
  • documentation and/or other materials provided with the distribution.

    *
    • Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
  • may be used to endorse or promote products derived from this software
  • without specific prior written permission.

    *
  • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  • TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  • PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  • CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  • EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  • PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  • PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  • LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  • NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  • SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    */



    package com.jme3.system.jogl;



    import com.jme3.system.AppSettings;

    import java.awt.BorderLayout;

    import java.awt.Container;

    import java.awt.Dimension;

    import java.awt.DisplayMode;

    import java.awt.Frame;

    import java.awt.Toolkit;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

    import java.lang.reflect.InvocationTargetException;

    import java.util.concurrent.atomic.AtomicBoolean;

    import java.util.logging.Level;

    import java.util.logging.Logger;

    import javax.media.opengl.GLAutoDrawable;

    import javax.swing.JFrame;

    import javax.swing.SwingUtilities;



    public class JoglDisplay extends JoglAbstractDisplay {



    private static final Logger logger = Logger.getLogger(JoglDisplay.class.getName());



    protected AtomicBoolean windowCloseRequest = new AtomicBoolean(false);

    protected AtomicBoolean needClose = new AtomicBoolean(false);

    protected AtomicBoolean needRestart = new AtomicBoolean(false);

    protected boolean wasInited = false;

    protected Frame frame;



    public Type getType() {

    return Type.Display;

    }



    protected DisplayMode getFullscreenDisplayMode(DisplayMode[] modes, int width, int height, int bpp, int freq){

    for (DisplayMode mode : modes){

    if (mode.getWidth() == width

    && mode.getHeight() == height

    && (mode.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI

    || mode.getBitDepth() == bpp

    || (mode.getBitDepth() == 32 && bpp==24))

    && mode.getRefreshRate() == freq){

    return mode;

    }

    }

    return null;

    }



    protected void createGLFrame(){

    Container contentPane;

    if (useAwt){

    frame = new Frame(settings.getTitle());

    contentPane = frame;

    }else{

    frame = new JFrame(settings.getTitle());

    contentPane = ((JFrame)frame).getContentPane();

    }



    contentPane.setLayout(new BorderLayout());



    applySettings(settings);



    frame.setResizable(false);

    frame.setFocusable(true);



    // only add canvas after frame is visible

    contentPane.add(canvas, BorderLayout.CENTER);

    frame.pack();

    // frame.setSize(contentPane.getPreferredSize());



    if (device.getFullScreenWindow() == null){

    // now that canvas is attached,

    // determine optimal size to contain it



    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    frame.setLocation((screenSize.width - frame.getWidth()) / 2,

    (screenSize.height - frame.getHeight()) / 2);

    }



    frame.addWindowListener(new WindowAdapter() {

    @Override

    public void windowClosing(WindowEvent evt) {

    windowCloseRequest.set(true);

    }

    @Override

    public void windowActivated(WindowEvent evt) {

    active.set(true);

    }



    @Override

    public void windowDeactivated(WindowEvent evt) {

    active.set(false);

    }

    });

    }



    protected void applySettings(AppSettings settings){

    DisplayMode displayMode;

    if (settings.getWidth() <= 0 || settings.getHeight() <= 0){

    displayMode = device.getDisplayMode();

    settings.setResolution(displayMode.getWidth(), displayMode.getHeight());

    }else if (settings.isFullscreen()){

    displayMode = getFullscreenDisplayMode(device.getDisplayModes(),

    settings.getWidth(), settings.getHeight(),

    settings.getBitsPerPixel(), settings.getFrequency());

    if (displayMode == null)

    throw new RuntimeException(“Unable to find fullscreen display mode matching settings”);

    }else{

    displayMode = new DisplayMode(settings.getWidth(), settings.getHeight(), 0, 0);

    }



    // FIXME: seems to return false even though

    // it is supported…

    // if (!device.isDisplayChangeSupported()){

    // // must use current device mode if display mode change not supported

    // displayMode = device.getDisplayMode();

    // settings.setResolution(displayMode.getWidth(), displayMode.getHeight());

    // }



    frameRate = settings.getFrameRate();

    logger.log(Level.INFO, “Selected display mode: {0}x{1}x{2} @{3}”,

    new Object[]{displayMode.getWidth(),

    displayMode.getHeight(),

    displayMode.getBitDepth(),

    displayMode.getRefreshRate()});



    canvas.setSize(displayMode.getWidth(), displayMode.getHeight());



    DisplayMode prevDisplayMode = device.getDisplayMode();



    if (settings.isFullscreen() && device.isFullScreenSupported()){

    frame.setUndecorated(true);



    try{

    device.setFullScreenWindow(frame);

    if (!prevDisplayMode.equals(displayMode)

    && device.isDisplayChangeSupported()){

    device.setDisplayMode(displayMode);

    }

    } catch (Throwable t){

    logger.log(Level.SEVERE, “Failed to enter fullscreen mode”, t);

    device.setFullScreenWindow(null);

    }

    }else{

    if (!device.isFullScreenSupported()){

    logger.warning(“Fullscreen not supported.”);

    }else{

    frame.setUndecorated(false);

    device.setFullScreenWindow(null);

    }



    frame.setVisible(true);

    }

    }



    private void initInEDT(){

    initGLCanvas();



    createGLFrame();



    startGLCanvas();

    }



    public void init(GLAutoDrawable drawable){

    // prevent initializing twice on restart

    if (!wasInited){

    canvas.requestFocus();



    super.internalCreate();

    logger.info(“Display created.”);



    renderer.initialize();

    listener.initialize();



    wasInited = true;

    }

    }



    public void create(boolean waitFor){

    try {

    if (waitFor){

    try{

    SwingUtilities.invokeAndWait(new Runnable() {

    public void run() {

    initInEDT();

    }

    });

    } catch (InterruptedException ex) {

    listener.handleError(“Interrupted”, ex);

    }

    }else{

    SwingUtilities.invokeLater(new Runnable() {

    public void run() {

    initInEDT();

    }

    });

    }

    } catch (InvocationTargetException ex) {

    throw new AssertionError(); // can never happen

    }

    }



    public void destroy(boolean waitFor){

    needClose.set(true);

    if (waitFor){

    waitFor(false);

    }

    }



    public void restart() {

    if (created.get()){

    needRestart.set(true);

    }else{

    throw new IllegalStateException(“Display not started yet. Cannot restart”);

    }

    }



    public void setTitle(String title){

    if (frame != null)

    frame.setTitle(title);

    }



    /**
  • Callback.

    */

    public void display(GLAutoDrawable drawable) {

    if (needClose.get()) {

    listener.destroy();

    animator.stop();

    if (settings.isFullscreen()) {

    device.setFullScreenWindow(null);

    }

    frame.dispose();

    logger.info(“Display destroyed.”);

    super.internalDestroy();

    return;

    }



    if (windowCloseRequest.get()){

    listener.requestClose(false);

    windowCloseRequest.set(false);

    }



    if (needRestart.getAndSet(false)){

    // for restarting contexts

    if (frame.isVisible()){

    animator.stop();

    frame.dispose();

    createGLFrame();

    startGLCanvas();

    }

    }



    // boolean flush = autoFlush.get();

    // if (animator.isAnimating() != flush){

    // if (flush)

    // animator.stop();

    // else

    // animator.start();

    // }



    if (wasActive != active.get()){

    if (!wasActive){

    listener.gainFocus();

    wasActive = true;

    }else{

    listener.loseFocus();

    wasActive = false;

    }

    }



    listener.update();

    renderer.onFrame();

    }

    }

    [/java]
1 Like

This port works only if you call GLProfile.initSingleton() as soon as possible before any GUI task.

Please do NOT store GL instances. I have used GLContext.getCurrentGL() to fix some bugs.



Rather do this:

displayMode = new DisplayMode(settings.getWidth(), settings.getHeight(), DisplayMode.BIT_DEPTH_MULTI, DisplayMode.REFRESH_RATE_UNKNOWN);



instead of this:

displayMode = new DisplayMode(settings.getWidth(), settings.getHeight(), 0, 0);



Please read the Java documentation before writing such stupid things. The statement above crashes the JVM here.

Its your googlecode email and commit password, look in “My Profile”

1 Like
new DisplayMode(settings.getWidth(), settings.getHeight(), 0, 0);

1) This is how windowed mode is done in LWJGL, so it was ported over as-is to JOGL assuming it will work.
2) Exception should be thrown if the arguments are invalid, rather than crash on specific platform.
Momoko_Fan said:
1) This is how windowed mode is done in LWJGL, so it was ported over as-is to JOGL assuming it will work.
2) Exception should be thrown if the arguments are invalid, rather than crash on specific platform.

It has nothing to do with JOGL, java.awt.DisplayMode is an AWT class and a developer should never create its own instances of DisplayMode. We should only use existing instances returned by java.awt.GraphicsDevice.getDisplayMode(). I fixed these kinds of bug both in JMonkeyEngine and Ardor3D, it would be better not to suppose AWT works like LWJGL. A tougher fix would consist in using only these existing instances as I did in the JOGL renderer of Ardor3D and JMonkeyEngine 2.


I get this whereas I have the 2 JARs of JAI in my classpath:

java.lang.NoClassDefFoundError: javax/media/jai/ComponentSampleModelJAI
at org.geotools.io.image.TextImageReader$Spi.(TextImageReader.java:354)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at sun.misc.Service$LazyIterator.next(Service.java:271)
at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(IIORegistry.java:190)
at javax.imageio.spi.IIORegistry.(IIORegistry.java:121)
at javax.imageio.spi.IIORegistry.getDefaultInstance(IIORegistry.java:142)
at javax.imageio.ImageIO.(ImageIO.java:48)
at com.jme3.texture.plugins.AWTLoader.load(AWTLoader.java:165)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:233)
at com.jme3.asset.DesktopAssetManager.loadTexture(DesktopAssetManager.java:272)
at com.jme3.font.plugins.BitmapFontLoader.load(BitmapFontLoader.java:108)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:233)
at com.jme3.asset.DesktopAssetManager.loadFont(DesktopAssetManager.java:321)
at com.jme3.app.SimpleApplication.loadFPSText(SimpleApplication.java:146)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:167)
at com.jme3.system.jogl.JoglDisplay.init(JoglDisplay.java:204)
at com.jogamp.opengl.impl.GLDrawableHelper.init(GLDrawableHelper.java:113)
at com.jogamp.opengl.impl.GLDrawableHelper.init(GLDrawableHelper.java:126)
at javax.media.opengl.awt.GLCanvas$InitAction.run(GLCanvas.java:646)
at com.jogamp.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:284)
at javax.media.opengl.awt.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:677)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: java.lang.ClassNotFoundException: javax.media.jai.ComponentSampleModelJAI
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 30 more

Where did you get JAI??

I took the JARs here, version 1.1:
https://jai-imageio.dev.java.net/binary-builds.html

I think the port is almost ready...

Nobody is using JAI. jME3 doesn’t use it.

Momoko_Fan said:
Nobody is using JAI. jME3 doesn't use it.

Why do I get this exception then? It is strange.

In AWTLoader, when javax.imageio.ImageIO is used, it tries to use javax.media.jai.ComponentSampleModelJAI, why?