From 6ca111b13d896d9a21d6260f54395083d70dd3df Mon Sep 17 00:00:00 2001 From: shadowislord Date: Mon, 19 Jan 2015 18:14:48 -0500 Subject: [PATCH] Refactor renderer system * Support OpenGL ES 2 in GLRenderer (various error fixes) * Get rid of OpenGL 1 remenants * Other minor cleanups --- .../renderer/android/OGLESShaderRenderer.java | 13 +- .../main/java/com/jme3/material/Material.java | 6 +- .../java/com/jme3/renderer/RenderContext.java | 37 +- .../java/com/jme3/renderer/RenderManager.java | 27 +- .../main/java/com/jme3/renderer/Renderer.java | 41 +- .../java/com/jme3/renderer/opengl/GL.java | 5 + .../java/com/jme3/renderer/opengl/GL2.java | 2 + .../java/com/jme3/renderer/opengl/GLExt.java | 2 +- .../java/com/jme3/renderer/opengl/GLFbo.java | 1 + .../jme3/renderer/opengl/GLImageFormats.java | 1 + .../com/jme3/renderer/opengl/GLRenderer.java | 353 +++++++++--------- .../java/com/jme3/system/NullRenderer.java | 2 +- .../renderer/ios/IGLESShaderRenderer.java | 2 +- .../com/jme3/renderer/jogl/JoglRenderer.java | 23 +- .../java/com/jme3/system/jogl/JoglCanvas.java | 2 +- .../com/jme3/system/jogl/JoglDisplay.java | 2 +- .../com/jme3/system/jogl/JoglNewtCanvas.java | 2 +- .../com/jme3/system/jogl/JoglNewtDisplay.java | 2 +- .../jme3/system/jogl/JoglOffscreenBuffer.java | 2 +- .../java/com/jme3/renderer/lwjgl/LwjglGL.java | 6 +- .../jme3/renderer/lwjgl/LwjglRenderer.java | 16 +- .../com/jme3/renderer/lwjgl/TextureUtil.java | 4 +- .../system/lwjgl/LwjglAbstractDisplay.java | 2 +- .../system/lwjgl/LwjglOffscreenBuffer.java | 2 +- 24 files changed, 224 insertions(+), 331 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java index 0d906abea..bcfbf1c29 100644 --- a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java +++ b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java @@ -643,18 +643,12 @@ public class OGLESShaderRenderer implements Renderer { } } - public void onFrame() { + public void postFrame() { RendererUtil.checkGLErrorForced(); objManager.deleteUnused(this); } - - public void setWorldMatrix(Matrix4f worldMatrix) { - } - - public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { - } - + /*********************************************************************\ |* Shaders *| \*********************************************************************/ @@ -1072,9 +1066,6 @@ public class OGLESShaderRenderer implements Renderer { /*********************************************************************\ |* Framebuffers *| \*********************************************************************/ - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { - copyFrameBuffer(src, dst, true); - } public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { throw new RendererException("Copy framebuffer not implemented yet."); diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 4a6d04275..157b12922 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -1199,20 +1199,18 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { // send lighting information, if needed switch (techDef.getLightMode()) { case Disable: - r.setLighting(null); break; case SinglePass: int nbRenderedLights = 0; resetUniformsNotSetByCurrent(shader); - while(nbRenderedLights < lights.size()){ + while (nbRenderedLights < lights.size()) { nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights); r.setShader(shader); renderMeshFromGeometry(r, geom); } return; case FixedPipeline: - r.setLighting(lights); - break; + throw new IllegalArgumentException("OpenGL1 is not supported"); case MultiPass: // NOTE: Special case! resetUniformsNotSetByCurrent(shader); diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java index 8fa479e44..358460716 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -250,36 +250,6 @@ public class RenderContext { */ public IDList attribIndexList = new IDList(); - /** - * Ambient color (GL1 only) - */ - public ColorRGBA ambient; - - /** - * Diffuse color (GL1 only) - */ - public ColorRGBA diffuse; - - /** - * Specular color (GL1 only) - */ - public ColorRGBA specular; - - /** - * Material color (GL1 only) - */ - public ColorRGBA color; - - /** - * Shininess (GL1 only) - */ - public float shininess; - - /** - * Use vertex color (GL1 only) - */ - public boolean useVertexColor; - /** * depth tets function */ @@ -290,10 +260,11 @@ public class RenderContext { */ public RenderState.TestFunction alphaFunc = RenderState.TestFunction.Greater; - public int initialDrawBuf; public int initialReadBuf; + public ColorRGBA clearColor = new ColorRGBA(0,0,0,0); + /** * Reset the RenderContext to default GL state */ @@ -343,10 +314,8 @@ public class RenderContext { frontStencilFunction = RenderState.TestFunction.Always; backStencilFunction = RenderState.TestFunction.Always; - ambient = diffuse = specular = color = null; - shininess = 0; - useVertexColor = false; depthFunc = RenderState.TestFunction.LessOrEqual; alphaFunc = RenderState.TestFunction.Greater; + clearColor.set(0,0,0,0); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index 592ecf3cf..5e87ed350 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -82,7 +82,6 @@ public class RenderManager { private Material forcedMaterial = null; private String forcedTechnique = null; private RenderState forcedRenderState = null; - private boolean shader; private int viewX, viewY, viewWidth, viewHeight; private Matrix4f orthoMatrix = new Matrix4f(); private LightList filteredLightList = new LightList(null); @@ -476,11 +475,7 @@ public class RenderManager { * @param mat The world matrix to set */ public void setWorldMatrix(Matrix4f mat) { - if (shader) { - uniformBindingManager.setWorldMatrix(mat); - } else { - renderer.setWorldMatrix(mat); - } + uniformBindingManager.setWorldMatrix(mat); } /** @@ -927,19 +922,10 @@ public class RenderManager { } private void setViewProjection(Camera cam, boolean ortho) { - if (shader) { - if (ortho) { - uniformBindingManager.setCamera(cam, Matrix4f.IDENTITY, orthoMatrix, orthoMatrix); - } else { - uniformBindingManager.setCamera(cam, cam.getViewMatrix(), cam.getProjectionMatrix(), cam.getViewProjectionMatrix()); - } + if (ortho) { + uniformBindingManager.setCamera(cam, Matrix4f.IDENTITY, orthoMatrix, orthoMatrix); } else { - if (ortho) { - renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix); - } else { - renderer.setViewProjectionMatrices(cam.getViewMatrix(), - cam.getProjectionMatrix()); - } + uniformBindingManager.setCamera(cam, cam.getViewMatrix(), cam.getProjectionMatrix(), cam.getViewProjectionMatrix()); } } @@ -1087,10 +1073,6 @@ public class RenderManager { if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null); } - - public void setUsingShaders(boolean usingShaders) { - this.shader = usingShaders; - } /** * Called by the application to render any ViewPorts @@ -1110,7 +1092,6 @@ public class RenderManager { return; } - this.shader = renderer.getCaps().contains(Caps.GLSL100); uniformBindingManager.newFrame(); if (prof!=null) prof.appStep(AppStep.RenderPreviewViewPorts); diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java index aa06d626e..e3dd20c92 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java @@ -31,10 +31,8 @@ */ package com.jme3.renderer; -import com.jme3.light.LightList; import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; -import com.jme3.math.Matrix4f; import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer; import com.jme3.shader.Shader; @@ -55,6 +53,11 @@ import java.util.EnumSet; */ public interface Renderer { + /** + * Detects available capabilities of the GPU. + * + * Must be called prior to any other Renderer methods. + */ public void initialize(); /** @@ -113,24 +116,7 @@ public interface Renderer { /** * Called when a new frame has been rendered. */ - public void onFrame(); - - /** - * Set the world matrix to use. Does nothing if the Renderer is - * shader based. - * - * @param worldMatrix World matrix to use. - */ - public void setWorldMatrix(Matrix4f worldMatrix); - - /** - * Sets the view and projection matrices to use. Does nothing if the Renderer - * is shader based. - * - * @param viewMatrix The view matrix to use. - * @param projMatrix The projection matrix to use. - */ - public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix); + public void postFrame(); /** * Set the viewport location and resolution on the screen. @@ -160,16 +146,6 @@ public interface Renderer { */ public void clearClipRect(); - /** - * Set lighting state. - * Does nothing if the renderer is shader based. - * The lights should be provided in world space. - * Specify null to disable lighting. - * - * @param lights The light list to set. - */ - public void setLighting(LightList lights); - /** * Sets the shader to use for rendering. * If the shader has not been uploaded yet, it is compiled @@ -195,11 +171,6 @@ public interface Renderer { */ public void deleteShaderSource(ShaderSource source); - /** - * Copies contents from src to dst, scaling if necessary. - */ - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst); - /** * Copies contents from src to dst, scaling if necessary. * set copyDepth to false to only copy the color buffers. diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index b2ad41c36..1a4e880f0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -79,6 +79,9 @@ public interface GL { public static final int GL_INCR_WRAP = 0x8507; public static final int GL_INFO_LOG_LENGTH = 0x8B84; public static final int GL_INT = 0x1404; + public static final int GL_INVALID_ENUM = 0x500; + public static final int GL_INVALID_VALUE = 0x501; + public static final int GL_INVALID_OPERATION = 0x502; public static final int GL_INVERT = 0x150A; public static final int GL_KEEP = 0x1E00; public static final int GL_LEQUAL = 0x203; @@ -102,12 +105,14 @@ public interface GL { public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700; public static final int GL_NEVER = 0x200; + public static final int GL_NO_ERROR = 0x0; public static final int GL_NONE = 0x0; public static final int GL_NOTEQUAL = 0x205; public static final int GL_ONE = 0x1; public static final int GL_ONE_MINUS_DST_COLOR = 0x307; public static final int GL_ONE_MINUS_SRC_ALPHA = 0x303; public static final int GL_ONE_MINUS_SRC_COLOR = 0x301; + public static final int GL_OUT_OF_MEMORY = 0x505; public static final int GL_POINTS = 0x0; public static final int GL_POLYGON_OFFSET_FILL = 0x8037; public static final int GL_REPEAT = 0x2901; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java index e13aa029c..db09fdd02 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java @@ -62,6 +62,8 @@ public interface GL2 extends GL { public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; public static final int GL_READ_BUFFER = 0xC02; public static final int GL_RGB8 = 0x8051; + public static final int GL_STACK_OVERFLOW = 0x503; + public static final int GL_STACK_UNDERFLOW = 0x504; public static final int GL_TEXTURE_3D = 0x806F; public static final int GL_POINT_SPRITE = 0x8861; public static final int GL_TEXTURE_COMPARE_FUNC = 0x884D; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java index e184e7c1f..b3cc832a8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java @@ -43,7 +43,6 @@ import java.nio.IntBuffer; */ public interface GLExt extends GLFbo { - public static final int GL_ETC1_RGB8_OES = 0x8D64; public static final int GL_COMPRESSED_RGB8_ETC2 = 0x9274; public static final int GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; public static final int GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; @@ -56,6 +55,7 @@ public interface GLExt extends GLFbo { public static final int GL_DEPTH_COMPONENT32F = 0x8CAC; public static final int GL_DEPTH24_STENCIL8_EXT = 0x88F0; public static final int GL_DEPTH_STENCIL_EXT = 0x84F9; + public static final int GL_ETC1_RGB8_OES = 0x8D64; public static final int GL_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x8DBA; public static final int GL_FRAMEBUFFER_SRGB_EXT = 0x8DB9; public static final int GL_HALF_FLOAT_ARB = 0x140B; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java index 481a1c68b..0a0d10a24 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java @@ -60,6 +60,7 @@ public interface GLFbo { public static final int GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT = 0x8D56; public static final int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT = 0x8CDC; public static final int GL_FRAMEBUFFER_UNSUPPORTED_EXT = 0x8CDD; + public static final int GL_INVALID_FRAMEBUFFER_OPERATION_EXT = 0x506; public static final int GL_MAX_COLOR_ATTACHMENTS_EXT = 0x8CDF; public static final int GL_MAX_RENDERBUFFER_SIZE_EXT = 0x84E8; public static final int GL_READ_FRAMEBUFFER_BINDING_EXT = 0x8CAA; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java index e29b190f5..649d15876 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java @@ -126,6 +126,7 @@ public final class GLImageFormats { format(formatToGL, Format.RGB8, GLExt.GL_RGBA8, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); format(formatToGL, Format.RGBA8, GLExt.GL_RGBA8, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); } else { + // Actually, the internal format isn't used for OpenGL ES 2! This is the same as the above.. format(formatToGL, Format.Alpha8, GL.GL_RGBA4, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE); format(formatToGL, Format.Luminance8, GL.GL_RGB565, GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE); format(formatToGL, Format.Luminance8Alpha8, GL.GL_RGBA4, GL.GL_LUMINANCE_ALPHA, GL.GL_UNSIGNED_BYTE); diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index e6526dce6..6c6ccd19f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -70,6 +70,8 @@ public class GLRenderer implements Renderer { private static final Logger logger = Logger.getLogger(GLRenderer.class.getName()); private static final boolean VALIDATE_SHADER = false; + private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); private final StringBuilder stringBuf = new StringBuilder(250); private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); @@ -117,18 +119,6 @@ public class GLRenderer implements Renderer { this.texUtil = new TextureUtil(gl, gl2, glext); } - protected void updateNameBuffer() { - int len = stringBuf.length(); - - nameBuf.position(0); - nameBuf.limit(len); - for (int i = 0; i < len; i++) { - nameBuf.put((byte) stringBuf.charAt(i)); - } - - nameBuf.rewind(); - } - @Override public Statistics getStatistics() { return statistics; @@ -147,12 +137,8 @@ public class GLRenderer implements Renderer { return extensionSet; } - private static final Pattern VERSION = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); - - public static int extractVersion(String version) { - - Matcher m = VERSION.matcher(version); + Matcher m = GLVERSION_PATTERN.matcher(version); if (m.matches()) { int major = Integer.parseInt(m.group(1)); int minor = Integer.parseInt(m.group(2)); @@ -492,12 +478,6 @@ public class GLRenderer implements Renderer { invalidateState(); } - private void checkCap(Caps cap) { - if (!caps.contains(cap)) { - throw new UnsupportedOperationException("Required capability missing: " + cap.name()); - } - } - /*********************************************************************\ |* Render State *| \*********************************************************************/ @@ -516,11 +496,10 @@ public class GLRenderer implements Renderer { bits = GL.GL_COLOR_BUFFER_BIT; } if (depth) { - - //glClear(GL.GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false - //here s some link on openl board - //http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223 - //if depth clear is requested, we enable the depthMask + // glClear(GL.GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false + // here s some link on openl board + // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223 + // if depth clear is requested, we enable the depthMask if (context.depthWriteEnabled == false) { gl.glDepthMask(true); context.depthWriteEnabled = true; @@ -528,6 +507,8 @@ public class GLRenderer implements Renderer { bits |= GL.GL_DEPTH_BUFFER_BIT; } if (stencil) { + // May need to set glStencilMask(0xFF) here if we ever allow users + // to change the stencil mask. bits |= GL.GL_STENCIL_BUFFER_BIT; } if (bits != 0) { @@ -536,7 +517,10 @@ public class GLRenderer implements Renderer { } public void setBackgroundColor(ColorRGBA color) { - gl.glClearColor(color.r, color.g, color.b, color.a); + if (!context.clearColor.equals(color)) { + gl.glClearColor(color.r, color.g, color.b, color.a); + context.clearColor.set(color); + } } public void setAlphaToCoverage(boolean value) { @@ -608,30 +592,28 @@ public class GLRenderer implements Renderer { context.colorWriteEnabled = false; } - if (state.isPointSprite() && !context.pointSprite) { - // Only enable/disable sprite - if (context.boundTextures[0] != null) { - if (context.boundTextureUnit != 0) { - gl.glActiveTexture(GL.GL_TEXTURE0); - context.boundTextureUnit = 0; - } - if (gl2 != null) { + if (gl2 != null) { + if (state.isPointSprite() && !context.pointSprite) { + // Only enable/disable sprite + if (context.boundTextures[0] != null) { + if (context.boundTextureUnit != 0) { + gl.glActiveTexture(GL.GL_TEXTURE0); + context.boundTextureUnit = 0; + } gl2.glEnable(GL2.GL_POINT_SPRITE); gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE); } - } - context.pointSprite = true; - } else if (!state.isPointSprite() && context.pointSprite) { - if (context.boundTextures[0] != null) { - if (context.boundTextureUnit != 0) { - gl.glActiveTexture(GL.GL_TEXTURE0); - context.boundTextureUnit = 0; - } - if (gl2 != null) { + context.pointSprite = true; + } else if (!state.isPointSprite() && context.pointSprite) { + if (context.boundTextures[0] != null) { + if (context.boundTextureUnit != 0) { + gl.glActiveTexture(GL.GL_TEXTURE0); + context.boundTextureUnit = 0; + } gl2.glDisable(GL2.GL_POINT_SPRITE); gl2.glDisable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE); + context.pointSprite = false; } - context.pointSprite = false; } } @@ -858,24 +840,15 @@ public class GLRenderer implements Renderer { } } - public void onFrame() { + public void postFrame() { objManager.deleteUnused(this); -// statistics.clearFrame(); - } - - public void setWorldMatrix(Matrix4f worldMatrix) { - } - - public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { } /*********************************************************************\ |* Shaders *| \*********************************************************************/ protected void updateUniformLocation(Shader shader, Uniform uniform) { - stringBuf.setLength(0); - stringBuf.append(uniform.getName()).append('\0'); - int loc = gl.glGetUniformLocation(shader.getId(), stringBuf.toString()); + int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName()); if (loc < 0) { uniform.setLocation(-1); // uniform is not declared in shader @@ -1020,13 +993,6 @@ public class GLRenderer implements Renderer { } } - /* - * (Non-javadoc) - * Only used for fixed-function. Ignored. - */ - public void setLighting(LightList list) { - } - public int convertShaderType(ShaderType type) { switch (type) { case Fragment: @@ -1052,9 +1018,16 @@ public class GLRenderer implements Renderer { throw new RendererException("Cannot recompile shader source"); } + boolean gles2 = caps.contains(Caps.OpenGLES20); + String language = source.getLanguage(); + + if (gles2 && !language.equals("GLSL100")) { + throw new RendererException("This shader cannot run in OpenGL ES 2. " + + "Only GLSL 1.00 shaders are supported."); + } + // Upload shader source. // Merge the defines and source code. - String language = source.getLanguage(); stringBuf.setLength(0); if (language.startsWith("GLSL")) { int version = Integer.parseInt(language.substring(4)); @@ -1066,11 +1039,20 @@ public class GLRenderer implements Renderer { } stringBuf.append("\n"); } else { - // version 100 does not exist in desktop GLSL. - // put version 110 in that case to enable strict checking - stringBuf.append("#version 110\n"); + if (gles2) { + if (source.getType() == ShaderType.Fragment) { + // GLES2 requires precision qualifier. + stringBuf.append("precision mediump float;\n"); + } + } else { + // version 100 does not exist in desktop GLSL. + // put version 110 in that case to enable strict checking + // (Only enabled for desktop GL) + stringBuf.append("#version 110\n"); + } } } + stringBuf.append(source.getDefines()); stringBuf.append(source.getSource()); @@ -1309,8 +1291,7 @@ public class GLRenderer implements Renderer { throw ex; } } else { - throw new RendererException("EXT_framebuffer_blit required."); - // TODO: support non-blit copies? + throw new RendererException("Framebuffer blitting not supported by the video hardware"); } } @@ -1504,10 +1485,10 @@ public class GLRenderer implements Renderer { } if (!caps.contains(Caps.FrameBuffer)) { - throw new RendererException("Framebuffer objects are not supported" + - " by the video hardware"); + throw new RendererException("Framebuffer objects are not supported" + + " by the video hardware"); } - + // generate mipmaps for last FB if needed if (context.boundFB != null) { for (int i = 0; i < context.boundFB.getNumColorBuffers(); i++) { @@ -1518,14 +1499,18 @@ public class GLRenderer implements Renderer { setTexture(0, rb.getTexture()); int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace()); - if (gl2 != null) gl2.glEnable(textureType); + if (gl2 != null) { + gl2.glEnable(textureType); + } glfbo.glGenerateMipmapEXT(textureType); - if (gl2 != null) gl2.glDisable(textureType); + if (gl2 != null) { + gl2.glDisable(textureType); + } } } } - if (fb == null) { + if (fb == null) { // unbind any fbos if (context.boundFBO != 0) { glfbo.glBindFramebufferEXT(GLExt.GL_FRAMEBUFFER_EXT, 0); @@ -1579,7 +1564,7 @@ public class GLRenderer implements Renderer { gl2.glReadBuffer(GL.GL_NONE); context.boundReadBuf = -2; } - } + } } else { if (fb.getNumColorBuffers() > maxFBOAttachs) { throw new RendererException("Framebuffer has more color " @@ -1588,8 +1573,8 @@ public class GLRenderer implements Renderer { } if (fb.isMultiTarget()) { if (!caps.contains(Caps.FrameBufferMRT)) { - throw new RendererException("Multiple render targets " + - " are not supported by the video hardware"); + throw new RendererException("Multiple render targets " + + " are not supported by the video hardware"); } if (fb.getNumColorBuffers() > maxMRTFBOAttachs) { throw new RendererException("Framebuffer has more" @@ -1694,14 +1679,6 @@ public class GLRenderer implements Renderer { throw new RendererException("Multisample textures are not supported" + " by the video hardware."); } - if (type == Texture.Type.ThreeDimensional && gl2 == null) { - throw new RendererException("3D textures are not supported" + - " by the video hardware."); - } else if (type == Texture.Type.TwoDimensionalArray && !caps.contains(Caps.TextureArray)) { - throw new RendererException("Array textures are not supported" + - " by the video hardware."); - } - switch (type) { case TwoDimensional: @@ -1711,13 +1688,21 @@ public class GLRenderer implements Renderer { return GL.GL_TEXTURE_2D; } case TwoDimensionalArray: + if (!caps.contains(Caps.TextureArray)) { + throw new RendererException("Array textures are not supported" + + " by the video hardware."); + } if (samples > 1) { return GLExt.GL_TEXTURE_2D_MULTISAMPLE_ARRAY; } else { return GLExt.GL_TEXTURE_2D_ARRAY_EXT; } case ThreeDimensional: - return GL3.GL_TEXTURE_3D; + if (!caps.contains(Caps.OpenGL20)) { + throw new RendererException("3D textures are not supported" + + " by the video hardware."); + } + return GL2.GL_TEXTURE_3D; case CubeMap: if (face < 0) { return GL.GL_TEXTURE_CUBE_MAP; @@ -2140,7 +2125,7 @@ public class GLRenderer implements Renderer { //statistics.onVertexBufferUse(vb, false); } } - + int usage = convertUsage(vb.getUsage()); vb.getData().rewind(); @@ -2158,10 +2143,6 @@ public class GLRenderer implements Renderer { break; case Int: case UnsignedInt: - if (!caps.contains(Caps.IntegerIndexBuffer)) { - throw new RendererException("32-bit index buffers are not supported by the video hardware"); - } - glext.glBufferData(target, (IntBuffer) vb.getData(), usage); break; case Float: @@ -2230,108 +2211,103 @@ public class GLRenderer implements Renderer { throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); } - int programId = context.boundShaderProgram; + if (context.boundShaderProgram <= 0) { + throw new IllegalStateException("Cannot render mesh without shader bound"); + } + + Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); + int loc = attrib.getLocation(); + if (loc == -1) { + return; // not defined + } + if (loc == -2) { + loc = gl.glGetAttribLocation(context.boundShaderProgram, "in" + vb.getBufferType().name()); - if (programId > 0) { - Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); - int loc = attrib.getLocation(); - if (loc == -1) { - return; // not defined + // not really the name of it in the shader (inPosition) but + // the internal name of the enum (Position). + if (loc < 0) { + attrib.setLocation(-1); + return; // not available in shader. + } else { + attrib.setLocation(loc); } - if (loc == -2) { - stringBuf.setLength(0); - stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); - loc = gl.glGetAttribLocation(programId, stringBuf.toString()); + } - // not really the name of it in the shader (inPosition\0) but - // the internal name of the enum (Position). - if (loc < 0) { - attrib.setLocation(-1); - return; // not available in shader. - } else { - attrib.setLocation(loc); - } - } - - if (vb.isInstanced()) { - if (!caps.contains(Caps.MeshInstancing)) { - throw new RendererException("Instancing is required, " - + "but not supported by the " - + "graphics hardware"); - } + if (vb.isInstanced()) { + if (!caps.contains(Caps.MeshInstancing)) { + throw new RendererException("Instancing is required, " + + "but not supported by the " + + "graphics hardware"); } - int slotsRequired = 1; - if (vb.getNumComponents() > 4) { - if (vb.getNumComponents() % 4 != 0) { - throw new RendererException("Number of components in multi-slot " - + "buffers must be divisible by 4"); - } - slotsRequired = vb.getNumComponents() / 4; + } + int slotsRequired = 1; + if (vb.getNumComponents() > 4) { + if (vb.getNumComponents() % 4 != 0) { + throw new RendererException("Number of components in multi-slot " + + "buffers must be divisible by 4"); } + slotsRequired = vb.getNumComponents() / 4; + } - if (vb.isUpdateNeeded() && idb == null) { - updateBufferData(vb); - } + if (vb.isUpdateNeeded() && idb == null) { + updateBufferData(vb); + } - VertexBuffer[] attribs = context.boundAttribs; - for (int i = 0; i < slotsRequired; i++) { - if (!context.attribIndexList.moveToNew(loc + i)) { - gl.glEnableVertexAttribArray(loc + i); - //System.out.println("Enabled ATTRIB IDX: "+loc); - } + VertexBuffer[] attribs = context.boundAttribs; + for (int i = 0; i < slotsRequired; i++) { + if (!context.attribIndexList.moveToNew(loc + i)) { + gl.glEnableVertexAttribArray(loc + i); + } + } + if (attribs[loc] != vb) { + // NOTE: Use id from interleaved buffer if specified + int bufId = idb != null ? idb.getId() : vb.getId(); + assert bufId != -1; + if (context.boundArrayVBO != bufId) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, bufId); + context.boundArrayVBO = bufId; + //statistics.onVertexBufferUse(vb, true); + } else { + //statistics.onVertexBufferUse(vb, false); } - if (attribs[loc] != vb) { - // NOTE: Use id from interleaved buffer if specified - int bufId = idb != null ? idb.getId() : vb.getId(); - assert bufId != -1; - if (context.boundArrayVBO != bufId) { - gl.glBindBuffer(GL.GL_ARRAY_BUFFER, bufId); - context.boundArrayVBO = bufId; - //statistics.onVertexBufferUse(vb, true); - } else { - //statistics.onVertexBufferUse(vb, false); - } - if (slotsRequired == 1) { - gl.glVertexAttribPointer(loc, - vb.getNumComponents(), + if (slotsRequired == 1) { + gl.glVertexAttribPointer(loc, + vb.getNumComponents(), + convertFormat(vb.getFormat()), + vb.isNormalized(), + vb.getStride(), + vb.getOffset()); + } else { + for (int i = 0; i < slotsRequired; i++) { + // The pointer maps the next 4 floats in the slot. + // E.g. + // P1: XXXX____________XXXX____________ + // P2: ____XXXX____________XXXX________ + // P3: ________XXXX____________XXXX____ + // P4: ____________XXXX____________XXXX + // stride = 4 bytes in float * 4 floats in slot * num slots + // offset = 4 bytes in float * 4 floats in slot * slot index + gl.glVertexAttribPointer(loc + i, + 4, convertFormat(vb.getFormat()), vb.isNormalized(), - vb.getStride(), - vb.getOffset()); - } else { - for (int i = 0; i < slotsRequired; i++) { - // The pointer maps the next 4 floats in the slot. - // E.g. - // P1: XXXX____________XXXX____________ - // P2: ____XXXX____________XXXX________ - // P3: ________XXXX____________XXXX____ - // P4: ____________XXXX____________XXXX - // stride = 4 bytes in float * 4 floats in slot * num slots - // offset = 4 bytes in float * 4 floats in slot * slot index - gl.glVertexAttribPointer(loc + i, - 4, - convertFormat(vb.getFormat()), - vb.isNormalized(), - 4 * 4 * slotsRequired, - 4 * 4 * i); - } + 4 * 4 * slotsRequired, + 4 * 4 * i); } + } - for (int i = 0; i < slotsRequired; i++) { - int slot = loc + i; - if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) { - // non-instanced -> instanced - glext.glVertexAttribDivisorARB(slot, vb.getInstanceSpan()); - } else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) { - // instanced -> non-instanced - glext.glVertexAttribDivisorARB(slot, 0); - } - attribs[slot] = vb; + for (int i = 0; i < slotsRequired; i++) { + int slot = loc + i; + if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) { + // non-instanced -> instanced + glext.glVertexAttribDivisorARB(slot, vb.getInstanceSpan()); + } else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) { + // instanced -> non-instanced + glext.glVertexAttribDivisorARB(slot, 0); } + attribs[slot] = vb; } - } else { - throw new IllegalStateException("Cannot render mesh without shader bound"); } } @@ -2354,6 +2330,21 @@ public class GLRenderer implements Renderer { throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); } + switch (indexBuf.getFormat()) { + case UnsignedShort: + // OK: Works on all platforms. + break; + case UnsignedInt: + // Requres extension on OpenGL ES 2. + if (!caps.contains(Caps.IntegerIndexBuffer)) { + throw new RendererException("32-bit index buffers are not supported by the video hardware"); + } + break; + default: + // What is this? + throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat()); + } + if (indexBuf.isUpdateNeeded()) { updateBufferData(indexBuf); } diff --git a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java index 06015ecd3..f2e029af4 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java +++ b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java @@ -80,7 +80,7 @@ public class NullRenderer implements Renderer { public void setDepthRange(float start, float end) { } - public void onFrame() { + public void postFrame() { } public void setWorldMatrix(Matrix4f worldMatrix) { diff --git a/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java b/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java index e0b6e0a08..f219ddfe7 100644 --- a/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java +++ b/jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java @@ -335,7 +335,7 @@ public class IGLESShaderRenderer implements Renderer { /** * Called when a new frame has been rendered. */ - public void onFrame() { + public void postFrame() { logger.log(Level.FINE, "IGLESShaderRenderer onFrame"); //JmeIosGLES.checkGLErrorForced(); JmeIosGLES.checkGLError(); diff --git a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java index 8fa9d144a..63effbccd 100644 --- a/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java +++ b/jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java @@ -832,17 +832,9 @@ public class JoglRenderer implements Renderer { } @Override - public void onFrame() { + public void postFrame() { objManager.deleteUnused(this); } - - @Override - public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { - } - - @Override - public void setWorldMatrix(Matrix4f worldMatrix) { - } /*********************************************************************\ |* Shaders *| @@ -997,14 +989,6 @@ public class JoglRenderer implements Renderer { uniform.reset(); // e.g check location again } } - - /* - * (Non-javadoc) - * Only used for fixed-function. Ignored. - */ - @Override - public void setLighting(LightList list) { - } public int convertShaderType(Shader.ShaderType type) { switch (type) { @@ -1248,11 +1232,6 @@ public class JoglRenderer implements Renderer { /*********************************************************************\ |* Framebuffers *| \*********************************************************************/ - @Override - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { - copyFrameBuffer(src, dst, true); - } - @Override public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { GL gl = GLContext.getCurrentGL(); diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java index a4646b44f..c4e97570e 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java @@ -125,7 +125,7 @@ public class JoglCanvas extends JoglAbstractDisplay implements JmeCanvasContext } listener.update(); - renderer.onFrame(); + renderer.postFrame(); } diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java index e095251f2..363ccd096 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java @@ -351,6 +351,6 @@ public class JoglDisplay extends JoglAbstractDisplay { } listener.update(); - renderer.onFrame(); + renderer.postFrame(); } } diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java index cb84c94a9..e4f46d8fb 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java @@ -145,7 +145,7 @@ public class JoglNewtCanvas extends JoglNewtAbstractDisplay implements JmeCanvas } listener.update(); - renderer.onFrame(); + renderer.postFrame(); } diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java index 0eb2d842e..011002aff 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java @@ -239,7 +239,7 @@ public class JoglNewtDisplay extends JoglNewtAbstractDisplay { } listener.update(); - renderer.onFrame(); + renderer.postFrame(); } } diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java index 6355e9703..505808878 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java @@ -101,7 +101,7 @@ public class JoglOffscreenBuffer extends JoglContext implements Runnable { listener.update(); checkGLError(); - renderer.onFrame(); + renderer.postFrame(); int frameRate = settings.getFrameRate(); if (frameRate >= 1) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java index 47e2a9185..89f3edce0 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java @@ -343,11 +343,13 @@ public class LwjglGL implements GL, GL2 { } public int glGetAttribLocation(int param1, String param2) { - return GL20.glGetAttribLocation(param1, param2); + // NOTE: LWJGL requires null-terminated strings + return GL20.glGetAttribLocation(param1, param2 + "\0"); } public int glGetUniformLocation(int param1, String param2) { - return GL20.glGetUniformLocation(param1, param2); + // NOTE: LWJGL requires null-terminated strings + return GL20.glGetUniformLocation(param1, param2 + "\0"); } public void glShaderSource(int param1, String[] param2, IntBuffer param3) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java index 74ee6de88..0013a1f75 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java @@ -424,11 +424,13 @@ public class LwjglRenderer { logger.log(Level.FINER, "Texture Multisample Depth Samples: {0}", maxDepthTexSamples); } - glGetInteger(GL_MAX_DRAW_BUFFERS, intBuf16); - maxMRTFBOAttachs = intBuf16.get(0); - if (maxMRTFBOAttachs > 1) { - caps.add(Caps.FrameBufferMRT); - logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); + if (hasExtension("GL_ARB_draw_buffers")) { + glGetInteger(GL_MAX_DRAW_BUFFERS, intBuf16); + maxMRTFBOAttachs = intBuf16.get(0); + if (maxMRTFBOAttachs > 1) { + caps.add(Caps.FrameBufferMRT); + logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); + } } } @@ -832,7 +834,7 @@ public class LwjglRenderer { } } - public void onFrame() { + public void postFrame() { objManager.deleteUnused(this); // statistics.clearFrame(); } @@ -1945,7 +1947,7 @@ public class LwjglRenderer { // Image does not have mipmaps, but they are required. // Generate from base level. - if (!caps.contains(Caps.OpenGL30)) { + if (!caps.contains(Caps.OpenGL30) && !caps.contains(Caps.OpenGLES20)) { glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE); img.setMipmapsGenerated(true); } else { diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java index bcd9cb8de..41dddd6ae 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java +++ b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java @@ -42,7 +42,7 @@ import java.util.EnumSet; import java.util.logging.Level; import java.util.logging.Logger; import static org.lwjgl.opengl.ARBDepthBufferFloat.*; -import org.lwjgl.opengl.ARBES3Compatibility; +import static org.lwjgl.opengl.ARBES3Compatibility.*; import static org.lwjgl.opengl.ARBHalfFloatPixel.*; import static org.lwjgl.opengl.ARBTextureFloat.*; import static org.lwjgl.opengl.ARBTextureMultisample.*; @@ -139,7 +139,7 @@ class TextureUtil { // ETC1 support on regular OpenGL requires ES3 compatibility extension. // NOTE: ETC2 is backwards compatible with ETC1, so we can // upload ETC1 textures as ETC2. - setFormat(Format.ETC1, ARBES3Compatibility.GL_COMPRESSED_RGB8_ETC2, GL_RGB, GL_UNSIGNED_BYTE, true); + setFormat(Format.ETC1, GL_COMPRESSED_RGB8_ETC2, GL_RGB, GL_UNSIGNED_BYTE, true); } //sRGB formats diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java index 2168cf0a2..f0a157196 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java @@ -184,7 +184,7 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna // Subclasses just call GLObjectManager clean up objects here // it is safe .. for now. - renderer.onFrame(); + renderer.postFrame(); } /** diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java index 82109abda..acec23768 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java @@ -125,7 +125,7 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable { listener.update(); checkGLError(); - renderer.onFrame(); + renderer.postFrame(); int frameRate = settings.getFrameRate(); if (frameRate >= 1) {