|
|
|
@ -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,8 +1485,8 @@ 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
|
|
|
|
@ -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; |
|
|
|
@ -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"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (programId > 0) { |
|
|
|
|
Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); |
|
|
|
|
int loc = attrib.getLocation(); |
|
|
|
|
if (loc == -1) { |
|
|
|
|
return; // not defined
|
|
|
|
|
} |
|
|
|
|
if (loc == -2) { |
|
|
|
|
stringBuf.setLength(0); |
|
|
|
|
stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); |
|
|
|
|
loc = gl.glGetAttribLocation(programId, stringBuf.toString()); |
|
|
|
|
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()); |
|
|
|
|
|
|
|
|
|
// 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); |
|
|
|
|
} |
|
|
|
|
// 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 (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); |
|
|
|
|
} |
|
|
|
|