Added support for single primitive input/output parameters.

This commit is contained in:
Ioannis Tsakpinis 2010-03-14 23:24:40 +00:00
parent e97e601894
commit 94a4c50a83
63 changed files with 1309 additions and 444 deletions

View file

@ -33,45 +33,41 @@ package org.lwjgl.opengl;
import org.lwjgl.BufferUtils;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.nio.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
/** @author spasi */
final class StringUtils {
final class APIUtils {
private static final int INITIAL_BUFFER_SIZE = 256;
private static final int INITIAL_LENGTHS_SIZE = 4;
private static final int BUFFERS_SIZE = 32;
private static final ThreadLocal arrayTL = new ThreadLocal() {
protected Object initialValue() {
return new char[INITIAL_BUFFER_SIZE];
}
protected Object initialValue() { return new char[INITIAL_BUFFER_SIZE]; }
};
private static final ThreadLocal bufferTL = new ThreadLocal() {
protected Object initialValue() {
return BufferUtils.createByteBuffer(INITIAL_BUFFER_SIZE);
}
protected Object initialValue() { return BufferUtils.createByteBuffer(INITIAL_BUFFER_SIZE); }
};
private static final ThreadLocal lengthsTL = new ThreadLocal() {
protected Object initialValue() {
return BufferUtils.createIntBuffer(INITIAL_LENGTHS_SIZE);
}
protected Object initialValue() { return BufferUtils.createIntBuffer(INITIAL_LENGTHS_SIZE); }
};
private static final ThreadLocal infiniteSeqTL = new ThreadLocal() {
protected Object initialValue() {
return new InfiniteCharSequence();
}
protected Object initialValue() { return new InfiniteCharSequence(); }
};
private static final ThreadLocal buffersTL = new ThreadLocal() {
protected Object initialValue() { return new Buffers(); }
};
private static CharsetEncoder encoder = Charset.forName("US-ASCII").newEncoder();
private StringUtils() {
private APIUtils() {
}
private static char[] getArray(final int size) {
@ -89,7 +85,7 @@ final class StringUtils {
return array;
}
static ByteBuffer getBuffer(final int size) {
static ByteBuffer getBufferByte(final int size) {
ByteBuffer buffer = (ByteBuffer)bufferTL.get();
if ( buffer.capacity() < size ) {
@ -99,13 +95,13 @@ final class StringUtils {
buffer = BufferUtils.createByteBuffer(size);
bufferTL.set(buffer);
}
} else
buffer.clear();
buffer.clear();
return buffer;
}
private static ByteBuffer getBufferOffset(final int size) {
private static ByteBuffer getBufferByteOffset(final int size) {
ByteBuffer buffer = (ByteBuffer)bufferTL.get();
if ( buffer.capacity() < size ) {
@ -124,6 +120,20 @@ final class StringUtils {
return buffer;
}
static ShortBuffer getBufferShort() { return ((Buffers)buffersTL.get()).shorts; }
static IntBuffer getBufferInt() { return ((Buffers)buffersTL.get()).ints; }
static LongBuffer getBufferLong() { return ((Buffers)buffersTL.get()).longs; }
static FloatBuffer getBufferFloat() { return ((Buffers)buffersTL.get()).floats; }
static DoubleBuffer getBufferDouble() { return ((Buffers)buffersTL.get()).doubles; }
static IntBuffer getLengths() {
return getLengths(1);
}
static IntBuffer getLengths(final int size) {
IntBuffer lengths = (IntBuffer)lengthsTL.get();
@ -134,16 +144,22 @@ final class StringUtils {
lengths = BufferUtils.createIntBuffer(size);
lengthsTL.set(lengths);
}
} else
lengths.clear();
lengths.clear();
return lengths;
}
static InfiniteCharSequence getInfiniteSeq() {
private static InfiniteCharSequence getInfiniteSeq() {
return (InfiniteCharSequence)infiniteSeqTL.get();
}
private static void encode(final ByteBuffer buffer, final CharSequence string) {
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
}
/**
* Reads a byte string from the specified buffer.
*
@ -161,12 +177,6 @@ final class StringUtils {
return new String(charArray, 0, length);
}
private static void encode(final ByteBuffer buffer, final CharSequence string) {
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
infiniteSeq.setString(string);
encoder.encode(infiniteSeq.buffer, buffer, true);
}
/**
* Returns a buffer containing the specified string as bytes.
*
@ -175,7 +185,7 @@ final class StringUtils {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence string) {
final ByteBuffer buffer = getBuffer(string.length());
final ByteBuffer buffer = getBufferByte(string.length());
encode(buffer, string);
@ -190,8 +200,8 @@ final class StringUtils {
*
* @return the String as a ByteBuffer
*/
static ByteBuffer getBufferOffset(final CharSequence string, final int offset) {
final ByteBuffer buffer = getBufferOffset(offset + string.length());
static ByteBuffer getBuffer(final CharSequence string, final int offset) {
final ByteBuffer buffer = getBufferByteOffset(offset + string.length());
encode(buffer, string);
@ -207,7 +217,7 @@ final class StringUtils {
* @return the String as a ByteBuffer
*/
static ByteBuffer getBufferNT(final CharSequence string) {
final ByteBuffer buffer = getBuffer(string.length() + 1);
final ByteBuffer buffer = getBufferByte(string.length() + 1);
encode(buffer, string);
@ -216,7 +226,7 @@ final class StringUtils {
return buffer;
}
private static int getTotalLength(final CharSequence[] strings) {
static int getTotalLength(final CharSequence[] strings) {
int length = 0;
for ( int i = 0; i < strings.length; i++ )
length += strings[i].length();
@ -232,7 +242,7 @@ final class StringUtils {
* @return the Strings as a ByteBuffer
*/
static ByteBuffer getBuffer(final CharSequence[] strings) {
final ByteBuffer buffer = getBuffer(getTotalLength(strings));
final ByteBuffer buffer = getBufferByte(getTotalLength(strings));
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
for ( int i = 0; i < strings.length; i++ ) {
@ -253,7 +263,7 @@ final class StringUtils {
* @return the Strings as a ByteBuffer
*/
static ByteBuffer getBufferNT(final CharSequence[] strings) {
final ByteBuffer buffer = getBuffer(getTotalLength(strings) + strings.length);
final ByteBuffer buffer = getBufferByte(getTotalLength(strings) + strings.length);
final InfiniteCharSequence infiniteSeq = getInfiniteSeq();
for ( int i = 0; i < strings.length; i++ ) {
@ -321,4 +331,24 @@ final class StringUtils {
}
}
private static class Buffers {
final ShortBuffer shorts;
final IntBuffer ints;
final LongBuffer longs;
final FloatBuffer floats;
final DoubleBuffer doubles;
Buffers() {
shorts = BufferUtils.createShortBuffer(BUFFERS_SIZE);
ints = BufferUtils.createIntBuffer(BUFFERS_SIZE);
longs = BufferUtils.createLongBuffer(BUFFERS_SIZE);
floats = BufferUtils.createFloatBuffer(BUFFERS_SIZE);
doubles = BufferUtils.createDoubleBuffer(BUFFERS_SIZE);
}
}
}

View file

@ -31,17 +31,13 @@
*/
package org.lwjgl.test.opengl;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.*;
import java.nio.IntBuffer;
import java.util.Random;
/**
* @author spasi <spasi@users.sourceforge.net>
*/
/** @author spasi <spasi@users.sourceforge.net> */
public final class SyncTest {
private SyncTest() {
@ -131,9 +127,7 @@ public final class SyncTest {
System.out.println("Unexpected wait status: 0x" + Integer.toHexString(status));
}
IntBuffer property = BufferUtils.createIntBuffer(1);
GL32.glGetSync(sync, GL32.GL_SYNC_STATUS, null, property);
System.out.println("Sync Status: " + (property.get(0) == GL32.GL_UNSIGNALED ? "UNSIGNALED" : "SIGNALED"));
System.out.println("Sync Status: " + (GL32.glGetSync(sync, GL32.GL_SYNC_STATUS) == GL32.GL_UNSIGNALED ? "UNSIGNALED" : "SIGNALED"));
GL32.glDeleteSync(sync);

View file

@ -44,7 +44,6 @@ package org.lwjgl.test.opengl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
@ -191,9 +190,7 @@ public final class VBOTest {
System.out.println("ARB VBO not supported!");
System.exit(1);
}
IntBuffer int_buffer = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
ARBBufferObject.glGenBuffersARB(int_buffer);
buffer_id = int_buffer.get(0);
buffer_id = ARBBufferObject.glGenBuffersARB();
ARBBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, buffer_id);
vertices = ByteBuffer.allocateDirect(2 * 4 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertices.put(-50).put(-50).put(50).put(-50).put(50).put(50).put(-50).put(50);
@ -206,9 +203,7 @@ public final class VBOTest {
* Cleanup
*/
private static void cleanup() {
IntBuffer int_buffer = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
int_buffer.put(0, buffer_id);
ARBBufferObject.glDeleteBuffersARB(int_buffer);
ARBBufferObject.glDeleteBuffersARB(buffer_id);
Display.destroy();
}
}

View file

@ -37,21 +37,18 @@
*/
package org.lwjgl.test.opengl.shaders;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBProgram;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.GL11;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
abstract class Shader {
private static final IntBuffer int_buffer = BufferUtils.createIntBuffer(16);
protected static IntBuffer programBuffer = BufferUtils.createIntBuffer(1);
protected static ByteBuffer fileBuffer = BufferUtils.createByteBuffer(1024 * 10);
protected Shader() {
@ -61,18 +58,6 @@ abstract class Shader {
abstract void cleanup();
/**
* Obtain a GL integer value from the driver
*
* @param gl_enum The GL value you want
*
* @return the integer value
*/
public static int glGetInteger(int gl_enum) {
GL11.glGetInteger(gl_enum, int_buffer);
return int_buffer.get(0);
}
protected static String getShaderText(String file) {
String shader = null;
@ -107,7 +92,7 @@ abstract class Shader {
protected static void checkProgramError(String programFile, String programSource) {
if ( GL11.glGetError() == GL11.GL_INVALID_OPERATION ) {
final int errorPos = glGetInteger(ARBProgram.GL_PROGRAM_ERROR_POSITION_ARB);
final int errorPos = GL11.glGetInteger(ARBProgram.GL_PROGRAM_ERROR_POSITION_ARB);
int lineStart = 0;
int lineEnd = -1;
for ( int i = 0; i < programSource.length(); i++ ) {
@ -140,9 +125,7 @@ abstract class Shader {
}
protected static void printShaderObjectInfoLog(String file, int ID) {
ARBShaderObjects.glGetObjectParameterARB(ID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, programBuffer);
final int logLength = programBuffer.get(0);
final int logLength = ARBShaderObjects.glGetObjectParameteriARB(ID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB);
if ( logLength <= 1 )
return;
@ -153,9 +136,7 @@ abstract class Shader {
}
protected static void printShaderProgramInfoLog(int ID) {
ARBShaderObjects.glGetObjectParameterARB(ID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, programBuffer);
final int logLength = programBuffer.get(0);
final int logLength = ARBShaderObjects.glGetObjectParameteriARB(ID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB);
if ( logLength <= 1 )
return;

View file

@ -60,9 +60,7 @@ final class ShaderFP extends Shader {
vpFile = vpShaderFile;
vpSource = getShaderText(vpShaderFile);
ARBProgram.glGenProgramsARB(programBuffer);
vpID = programBuffer.get(0);
vpID = ARBProgram.glGenProgramsARB();
ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, vpID);
ARBProgram.glProgramStringARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, vpSource);
@ -73,9 +71,7 @@ final class ShaderFP extends Shader {
fpFile = fpShaderFile;
fpSource = getShaderText(fpShaderFile);
ARBProgram.glGenProgramsARB(programBuffer);
fpID = programBuffer.get(0);
fpID = ARBProgram.glGenProgramsARB();
ARBProgram.glBindProgramARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, fpID);
ARBProgram.glProgramStringARB(ARBFragmentProgram.GL_FRAGMENT_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, fpSource);
@ -104,11 +100,8 @@ final class ShaderFP extends Shader {
}
void cleanup() {
programBuffer.put(0, vpID);
ARBProgram.glDeleteProgramsARB(programBuffer);
programBuffer.put(0, fpID);
ARBProgram.glDeleteProgramsARB(programBuffer);
ARBProgram.glDeleteProgramsARB(vpID);
ARBProgram.glDeleteProgramsARB(fpID);
}
}

View file

@ -70,8 +70,7 @@ final class ShaderFSH extends Shader {
printShaderObjectInfoLog(this.vshFile, vshID);
ARBShaderObjects.glGetObjectParameterARB(vshID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( ARBShaderObjects.glGetObjectParameteriARB(vshID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE )
ShadersTest.kill("A compilation error occured in a vertex shader.");
// Initialize the fragment shader.
@ -84,8 +83,7 @@ final class ShaderFSH extends Shader {
printShaderObjectInfoLog(this.fshFile, fshID);
ARBShaderObjects.glGetObjectParameterARB(fshID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( ARBShaderObjects.glGetObjectParameteriARB(fshID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE )
ShadersTest.kill("A compilation error occured in a fragment shader.");
// Initialize the shader program.
@ -98,8 +96,7 @@ final class ShaderFSH extends Shader {
printShaderProgramInfoLog(programID);
ARBShaderObjects.glGetObjectParameterARB(programID, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( ARBShaderObjects.glGetObjectParameteriARB(programID, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE )
ShadersTest.kill("A linking error occured in a shader program.");
uniformLocation = getUniformLocation(programID, "UNIFORMS");

View file

@ -70,8 +70,7 @@ final class ShaderUNI extends Shader {
printShaderObjectInfoLog(file, shaderID);
GL20.glGetShader(shaderID, GL20.GL_COMPILE_STATUS, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( GL20.glGetShader(shaderID, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE )
ShadersTest.kill("A compilation error occured in a vertex shader.");
programID = GL20.glCreateProgram();
@ -81,27 +80,19 @@ final class ShaderUNI extends Shader {
printShaderProgramInfoLog(programID);
GL20.glGetProgram(programID, GL20.GL_LINK_STATUS, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( GL20.glGetProgram(programID, GL20.GL_LINK_STATUS) == GL11.GL_FALSE )
ShadersTest.kill("A linking error occured in a shader program.");
final String[] uniformNames = { "uniformA", "uniformB" };
IntBuffer indexes = BufferUtils.createIntBuffer(uniformNames.length);
IntBuffer params = BufferUtils.createIntBuffer(uniformNames.length);
IntBuffer getBuffer = BufferUtils.createIntBuffer(16);
IntBuffer buffers = BufferUtils.createIntBuffer(1);
// Get uniform block index and data size
final int blockIndex = ARBUniformBufferObject.glGetUniformBlockIndex(programID, "test");
ARBUniformBufferObject.glGetActiveUniformBlock(programID, blockIndex, ARBUniformBufferObject.GL_UNIFORM_BLOCK_DATA_SIZE, getBuffer);
final int blockSize = getBuffer.get(0);
final int blockSize = ARBUniformBufferObject.glGetActiveUniformBlock(programID, blockIndex, ARBUniformBufferObject.GL_UNIFORM_BLOCK_DATA_SIZE);
System.out.println("blockSize = " + blockSize);
// Create uniform buffer object and allocate a ByteBuffer
GL15.glGenBuffers(buffers);
bufferID = buffers.get(0);
bufferID = GL15.glGenBuffers();
GL15.glBindBuffer(ARBUniformBufferObject.GL_UNIFORM_BUFFER, bufferID);
GL15.glBufferData(ARBUniformBufferObject.GL_UNIFORM_BUFFER, blockSize, GL15.GL_DYNAMIC_DRAW);
buffer = BufferUtils.createFloatBuffer(blockSize);
@ -111,6 +102,9 @@ final class ShaderUNI extends Shader {
ARBUniformBufferObject.glUniformBlockBinding(programID, blockIndex, 0);
// Get uniform information
IntBuffer indexes = BufferUtils.createIntBuffer(uniformNames.length);
IntBuffer params = BufferUtils.createIntBuffer(uniformNames.length);
ARBUniformBufferObject.glGetUniformIndices(programID, uniformNames, indexes);
uniformA_index = indexes.get(0);
uniformB_index = indexes.get(1);

View file

@ -53,9 +53,7 @@ final class ShaderVP extends Shader {
file = shaderFile;
source = getShaderText(shaderFile);
ARBProgram.glGenProgramsARB(programBuffer);
ID = programBuffer.get(0);
ID = ARBProgram.glGenProgramsARB();
ARBProgram.glBindProgramARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ID);
ARBProgram.glProgramStringARB(ARBVertexProgram.GL_VERTEX_PROGRAM_ARB, ARBProgram.GL_PROGRAM_FORMAT_ASCII_ARB, source);
@ -76,8 +74,7 @@ final class ShaderVP extends Shader {
}
void cleanup() {
programBuffer.put(0, ID);
ARBProgram.glDeleteProgramsARB(programBuffer);
ARBProgram.glDeleteProgramsARB(ID);
}
}

View file

@ -38,8 +38,6 @@
package org.lwjgl.test.opengl.shaders;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.GL11;
@ -64,8 +62,7 @@ final class ShaderVSH extends Shader {
printShaderObjectInfoLog(file, shaderID);
ARBShaderObjects.glGetObjectParameterARB(shaderID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( ARBShaderObjects.glGetObjectParameteriARB(shaderID, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE )
ShadersTest.kill("A compilation error occured in a vertex shader.");
programID = ARBShaderObjects.glCreateProgramObjectARB();
@ -75,8 +72,7 @@ final class ShaderVSH extends Shader {
printShaderProgramInfoLog(programID);
ARBShaderObjects.glGetObjectParameterARB(programID, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB, programBuffer);
if ( programBuffer.get(0) == GL11.GL_FALSE )
if ( ARBShaderObjects.glGetObjectParameteriARB(programID, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE )
ShadersTest.kill("A linking error occured in a shader program.");
uniformLocation = getUniformLocation(programID, "UNIFORMS");

View file

@ -44,4 +44,6 @@ import java.lang.annotation.ElementType;
@Target(ElementType.PARAMETER)
public @interface Constant {
String value();
/** If true, the original parameter will not be removed from the method. */
boolean keepParam() default false;
}

View file

@ -220,7 +220,7 @@ public class GLTypeMap implements TypeMap {
else if ( type.equals(boolean.class) )
return new Class[] { GLboolean.class };
else if ( type.equals(void.class) )
return new Class[] { GLvoid.class, GLstring.class };
return new Class[] { GLvoid.class, GLreturn.class };
else
return new Class[] { };
}
@ -244,7 +244,7 @@ public class GLTypeMap implements TypeMap {
else if ( PointerWrapper.class.isAssignableFrom(type) )
valid_types = new Class[] { GLpointer.class };
else if (void.class.equals(type) )
valid_types = new Class[] { GLstring.class };
valid_types = new Class[] { GLreturn.class };
else
valid_types = new Class[] { };
return valid_types;

View file

@ -32,19 +32,24 @@
package org.lwjgl.util.generator;
/**
* Methods annotated with @GLstring will return a String instead of void.
* When a method is annonated with @GLreturn, the specified output Buffer parameter
* will be used to return a single value. The primitive type will match the Buffer type.
* String will be returned if the Buffer is a ByteBuffer annotated with @GLchar.
*
* @author spasi
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@NativeType
@Target({ ElementType.METHOD })
public @interface GLstring {
/** The ByteBuffer argument that will be used to retrieve the String bytes. */
String string();
/** The argument that specifies the maximum number of bytes that may be read. */
String maxLength();
public @interface GLreturn {
/** The Buffer parameter to use as the method result. */
String value();
/** The argument that specifies the maximum number of bytes that may be read (String results only). */
String maxLength() default "";
/** If true, the maxLength value is going to be used when creating the String. */
boolean forceMaxLength() default false;
///** If we use the byte buffer for another parameter, an offset must be used. */
//String offset() default "";
}

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2002-2008 LWJGL Project
* 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 'LWJGL' 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 org.lwjgl.util.generator;
/**
* This annotation must be used when there are more than one CharSequence arguments in a method.
* TODO: Add support for CharSequence[] if/when we need it.
*
* @author spasi
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ ElementType.PARAMETER })
public @interface GLstringOffset {
/** An expression that will specify the offset from which this String will be written to the ByteBuffer. */
String value();
}

View file

@ -105,17 +105,19 @@ public class GeneratorProcessorFactory implements AnnotationProcessorFactory, Ro
}
if (typemap_classname == null)
throw new RuntimeException("No TypeMap class name specified with -Atypemap=<class-name>");
TypeDeclaration lastFile = null;
try {
TypeMap type_map = (TypeMap)(Class.forName(typemap_classname).newInstance());
for (TypeDeclaration typedecl : env.getSpecifiedTypeDeclarations()) {
lastFile = typedecl;
typedecl.accept(getDeclarationScanner(new GeneratorVisitor(env, type_map, generate_error_checks, context_specific), NO_OP));
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (Exception e) {
if ( lastFile == null )
throw new RuntimeException(e);
else
throw new RuntimeException("\n-- Failed to process template: " + lastFile.getQualifiedName() + " --", e);
}
}
}

View file

@ -81,7 +81,7 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
throw new RuntimeException("Method " + method.getSimpleName() + " throws checked exceptions");
validateParameters(method);
StripPostfix strip_annotation = method.getAnnotation(StripPostfix.class);
if (strip_annotation != null) {
if (strip_annotation != null && method.getAnnotation(Alternate.class) == null) {
String postfix_param_name = strip_annotation.value();
ParameterDeclaration postfix_param = Utils.findParameter(method, postfix_param_name);
if (Utils.isParameterMultiTyped(postfix_param))
@ -142,9 +142,9 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
if (!found_auto_size_param
&& param.getAnnotation(Result.class) == null
&& param.getAnnotation(Constant.class) == null
&& !Utils.isReturnString(method, param)
&& !Utils.isReturnParameter(method, param)
)
throw new RuntimeException(param + " has no Check, Result nor Constant annotation and no other parameters has" +
throw new RuntimeException(param + " has no Check, Result nor Constant annotation, is not the return parameter and no other parameter has" +
" an @AutoSize annotation on it in method " + method);
}
if (param.getAnnotation(CachedReference.class) != null && param.getAnnotation(Result.class) != null)
@ -249,10 +249,11 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
}
public void visitInterfaceDeclaration(InterfaceDeclaration d) {
File input = d.getPosition().file();
File output = new File(env.getOptions().get("-s") + '/' + d.getPackage().getQualifiedName().replace('.', '/'), Utils.getSimpleClassName(d) + ".java");
try {
// Skip this class if the output exists and the input has not been modified.
File input = d.getPosition().file();
File output = new File(env.getOptions().get("-s") + '/' + d.getPackage().getQualifiedName().replace('.', '/'), Utils.getSimpleClassName(d) + ".java");
if ( output.exists() && input.lastModified() < output.lastModified() )
return;
@ -260,7 +261,14 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
generateJavaSource(d);
if (d.getMethods().size() > 0)
generateNativeSource(d);
} catch (IOException e) {
} catch (Exception e) {
try {
// If anything goes wrong mid-gen, delete output to allow regen next time we run.
if ( output.exists() )
output.delete();
} catch (Exception e2) {
// ignore
}
throw new RuntimeException(e);
}
}

View file

@ -122,7 +122,7 @@ public class JavaMethodsGenerator {
}
} else if (
param.getAnnotation(Result.class) == null
&& (native_stub || (param.getAnnotation(Constant.class) == null && !Utils.isReturnString(method, param)))
&& (native_stub || ((param.getAnnotation(Constant.class) == null || param.getAnnotation(Constant.class).keepParam()) && !Utils.isReturnParameter(method, param)))
&& (getAutoTypeParameter(method, param) == null || mode != Mode.AUTOS)
)
{
@ -237,12 +237,9 @@ public class JavaMethodsGenerator {
if ( method.getAnnotation(GLpointer.class) != null )
writer.print("new " + method.getReturnType() + "(");
}
GLstring string_annotation = method.getAnnotation(GLstring.class);
if ( string_annotation != null ) {
if ( method.getAnnotation(GLreturn.class) != null ) {
has_result = true;
writer.println("IntBuffer " + string_annotation.string() + "_length = StringUtils.getLengths(1);");
writer.println("\t\tByteBuffer " + string_annotation.string() + " = StringUtils.getBuffer(" + string_annotation.maxLength() + ");");
writer.print("\t\t");
Utils.printGLReturnPre(writer, method, method.getAnnotation(GLreturn.class));
}
writer.print(Utils.getSimpleNativeMethodName(method, generate_error_checks, context_specific));
if (mode == Mode.BUFFEROBJECT)
@ -262,12 +259,10 @@ public class JavaMethodsGenerator {
// DISABLED: indirect buffer support
//printNondirectParameterCopies(writer, method, mode);
if (has_result) {
if ( string_annotation == null )
if ( method.getAnnotation(GLreturn.class) == null )
writer.println("\t\treturn " + Utils.RESULT_VAR_NAME + ";");
else {
writer.println("\t\t" + string_annotation.string() + ".limit(" + string_annotation.string() + "_length.get(0));");
writer.println("\t\treturn StringUtils.getString(" + string_annotation.string() + ");");
}
else
Utils.printGLReturnPost(writer, method, method.getAnnotation(GLreturn.class));
}
writer.println("\t}");
}
@ -403,22 +398,20 @@ public class JavaMethodsGenerator {
if (mode == Mode.BUFFEROBJECT && param.getAnnotation(BufferObject.class) != null) {
writer.print(param.getSimpleName() + Utils.BUFFER_OBJECT_PARAMETER_POSTFIX);
} else {
Class type = typeinfos_instance.get(param).getType();
boolean hide_buffer = mode == Mode.AUTOS && getAutoTypeParameter(method, param) != null;
if (hide_buffer)
writer.print("null");
else {
Class type = typeinfos_instance.get(param).getType();
if ( type == CharSequence.class || type == CharSequence[].class ) {
GLstringOffset offset_annotation = param.getAnnotation(GLstringOffset.class);
final String offset = Utils.getStringOffset(method, param);
writer.print("StringUtils.getBuffer");
if ( offset_annotation != null )
writer.print("Offset");
writer.print("APIUtils.getBuffer");
if ( param.getAnnotation(NullTerminated.class) != null )
writer.print("NT");
writer.print("(" + param.getSimpleName());
if ( offset_annotation != null )
writer.print(", " + offset_annotation.value());
if ( offset != null )
writer.print(", " + offset);
writer.print(")");
hide_buffer = true;
} else
@ -443,9 +436,10 @@ public class JavaMethodsGenerator {
writer.print(" << " + shifting);
if (check_annotation != null && check_annotation.canBeNull())
writer.print(" : 0");
} else if ( param.getAnnotation(GLstringOffset.class) != null )
writer.print(param.getAnnotation(GLstringOffset.class).value());
else
} else if ( type == CharSequence.class || type == CharSequence[].class ) {
final String offset = Utils.getStringOffset(method, param);
writer.print(offset == null ? "0" : offset);
} else
writer.print("0");
} else if ( param.getAnnotation(GLpointer.class) != null ) {
writer.print(".getPointer()");
@ -531,7 +525,7 @@ public class JavaMethodsGenerator {
(mode != Mode.BUFFEROBJECT || param.getAnnotation(BufferObject.class) == null) &&
(mode != Mode.AUTOS || getAutoTypeParameter(method, param) == null) &&
param.getAnnotation(Result.class) == null &&
!Utils.isReturnString(method, param) ) {
!Utils.isReturnParameter(method, param) ) {
String check_value = null;
boolean can_be_null = false;
Check check_annotation = param.getAnnotation(Check.class);
@ -589,8 +583,8 @@ public class JavaMethodsGenerator {
private static void printResultType(PrintWriter writer, MethodDeclaration method, boolean native_stub) {
if ( native_stub && method.getAnnotation(GLpointer.class) != null )
writer.print("long");
else if ( !native_stub && method.getAnnotation(GLstring.class) != null )
writer.print("String");
else if ( !native_stub && method.getAnnotation(GLreturn.class) != null )
writer.print(Utils.getMethodReturnType(method, method.getAnnotation(GLreturn.class), false));
else
writer.print(Utils.getMethodReturnType(method).toString());
}

View file

@ -62,34 +62,31 @@ public class JavaTypeTranslator implements TypeVisitor {
throw new RuntimeException(t + " is not allowed");
}
public void visitPrimitiveType(PrimitiveType t) {
switch (t.getKind()) {
public static Class getPrimitiveClassFromKind(PrimitiveType.Kind kind) {
switch ( kind ) {
case LONG:
type = long.class;
break;
return long.class;
case INT:
type = int.class;
break;
return int.class;
case DOUBLE:
type = double.class;
break;
return double.class;
case FLOAT:
type = float.class;
break;
return float.class;
case SHORT:
type = short.class;
break;
return short.class;
case BYTE:
type = byte.class;
break;
return byte.class;
case BOOLEAN:
type = boolean.class;
break;
return boolean.class;
default:
throw new RuntimeException(t.getKind() + " is not allowed");
throw new RuntimeException(kind + " is not allowed");
}
}
public void visitPrimitiveType(PrimitiveType t) {
type = getPrimitiveClassFromKind(t.getKind());
}
public void visitDeclaredType(DeclaredType t) {
throw new RuntimeException(t + " is not allowed");
}

View file

@ -71,17 +71,17 @@ public class PostfixTranslator implements TypeVisitor {
}
private static PrimitiveType.Kind getPrimitiveKindFromBufferClass(Class c) {
if (IntBuffer.class.equals(c))
if (IntBuffer.class.equals(c) || int.class.equals(c) )
return PrimitiveType.Kind.INT;
else if (DoubleBuffer.class.equals(c))
else if (DoubleBuffer.class.equals(c) || double.class.equals(c) )
return PrimitiveType.Kind.DOUBLE;
else if (ShortBuffer.class.equals(c))
else if (ShortBuffer.class.equals(c) || short.class.equals(c) )
return PrimitiveType.Kind.SHORT;
else if (ByteBuffer.class.equals(c))
else if (ByteBuffer.class.equals(c) || byte.class.equals(c) )
return PrimitiveType.Kind.BYTE;
else if (FloatBuffer.class.equals(c))
else if (FloatBuffer.class.equals(c) || float.class.equals(c))
return PrimitiveType.Kind.FLOAT;
else if (LongBuffer.class.equals(c))
else if (LongBuffer.class.equals(c) || long.class.equals(c) )
return PrimitiveType.Kind.LONG;
else
throw new RuntimeException(c + " is not allowed");
@ -127,7 +127,7 @@ public class PostfixTranslator implements TypeVisitor {
}
public void visitPrimitiveType(PrimitiveType t) {
throw new RuntimeException(t + " is not allowed");
visitPrimitiveTypeKind(t.getKind());
}
private void visitPrimitiveTypeKind(PrimitiveType.Kind kind) {

View file

@ -40,15 +40,17 @@ package org.lwjgl.util.generator;
* $Id$
*/
import com.sun.mirror.type.*;
import java.io.PrintWriter;
import java.nio.Buffer;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.*;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.PrimitiveType;
import com.sun.mirror.type.TypeMirror;
public class Utils {
public static final String TYPEDEF_POSTFIX = "PROC";
public static final String FUNCTION_POINTER_VAR_NAME = "function_pointer";
public static final String FUNCTION_POINTER_POSTFIX = "_pointer";
@ -209,6 +211,29 @@ public class Utils {
return result_type;
}
public static String getMethodReturnType(MethodDeclaration method, GLreturn return_annotation, boolean buffer) {
ParameterDeclaration return_param = null;
for ( ParameterDeclaration param : method.getParameters() ) {
if ( param.getSimpleName().equals(return_annotation.value()) ) {
return_param = param;
break;
}
}
if ( return_param == null )
throw new RuntimeException("The @GLreturn parameter \"" + return_annotation.value() + "\" could not be found in method: " + method);
PrimitiveType.Kind kind = NativeTypeTranslator.getPrimitiveKindFromBufferClass(Utils.getJavaType(return_param.getType()));
if ( return_param.getAnnotation(GLboolean.class) != null )
kind = PrimitiveType.Kind.BOOLEAN;
if ( kind == PrimitiveType.Kind.BYTE && (return_param.getAnnotation(GLchar.class) != null || return_param.getAnnotation(GLcharARB.class) != null) )
return "String";
else {
final String type = JavaTypeTranslator.getPrimitiveClassFromKind(kind).getName();
return buffer ? Character.toUpperCase(type.charAt(0)) + type.substring(1) : type;
}
}
public static boolean needResultSize(MethodDeclaration method) {
return getNIOBufferType(getMethodReturnType(method)) != null && method.getAnnotation(AutoResultSize.class) == null;
}
@ -273,9 +298,98 @@ public class Utils {
return method_name;
}
static boolean isReturnString(MethodDeclaration method, ParameterDeclaration param) {
GLstring string_annotation = method.getAnnotation(GLstring.class);
return string_annotation != null && string_annotation.string().equals(param.getSimpleName());
static boolean isReturnParameter(MethodDeclaration method, ParameterDeclaration param) {
GLreturn string_annotation = method.getAnnotation(GLreturn.class);
if ( string_annotation == null || !string_annotation.value().equals(param.getSimpleName()) )
return false;
if ( param.getAnnotation(OutParameter.class) == null )
throw new RuntimeException("The parameter specified in @GLreturn is not annotated with @OutParameter in method: " + method);
if ( param.getAnnotation(Check.class) != null )
throw new RuntimeException("The parameter specified in @GLreturn is annotated with @Check in method: " + method);
if ( param.getAnnotation(GLchar.class) != null && Utils.getJavaType(param.getType()).equals(ByteBuffer.class) && string_annotation.maxLength().length() == 0 )
throw new RuntimeException("The @GLreturn annotation is missing a maxLength parameter in method: " + method);
return true;
}
static String getStringOffset(MethodDeclaration method, ParameterDeclaration param) {
String offset = null;
for ( ParameterDeclaration p : method.getParameters() ) {
if ( param != null && p.getSimpleName().equals(param.getSimpleName()) )
break;
final Class type = Utils.getJavaType(p.getType());
if ( type.equals(CharSequence.class) ) {
if ( offset == null )
offset = p.getSimpleName() + ".length()";
else
offset += " + " + p.getSimpleName() + ".length()";
if ( p.getAnnotation(NullTerminated.class) != null ) offset += " + 1";
} else if ( type.equals(CharSequence[].class) ) {
if ( offset == null )
offset = "APIUtils.getTotalLength(" + p.getSimpleName() + ")";
else
offset += " + APIUtils.getTotalLength(" + p.getSimpleName() + ")";
if ( p.getAnnotation(NullTerminated.class) != null ) offset += " + " + p.getSimpleName() + ".length";
}
}
return offset;
}
static void printGLReturnPre(PrintWriter writer, MethodDeclaration method, GLreturn return_annotation) {
final String return_type = getMethodReturnType(method, return_annotation, true);
if ( "String".equals(return_type) ) {
if ( !return_annotation.forceMaxLength() ) {
writer.println("IntBuffer " + return_annotation.value() + "_length = APIUtils.getLengths();");
writer.print("\t\t");
}
writer.print("ByteBuffer " + return_annotation.value() + " = APIUtils.getBufferByte(" + return_annotation.maxLength());
/*
Params that use the return buffer will advance its position while filling it. When we return, the position will be
at the right spot for grabbing the returned string bytes. We only have to make sure that the original buffer was
large enough to hold everything, so that no re-allocations happen while filling.
*/
final String offset = getStringOffset(method, null);
if ( offset != null )
writer.print(" + " + offset);
writer.println(");");
} else {
final String buffer_type = "Boolean".equals(return_type) ? "Byte" : return_type;
writer.print(buffer_type + "Buffer " + return_annotation.value() + " = APIUtils.getBuffer" + buffer_type + "(");
if ( "Byte".equals(buffer_type) )
writer.print('1');
writer.println(");");
}
writer.print("\t\t");
}
static void printGLReturnPost(PrintWriter writer, MethodDeclaration method, GLreturn return_annotation) {
final String return_type = getMethodReturnType(method, return_annotation, true);
if ( "String".equals(return_type) ) {
writer.print("\t\t" + return_annotation.value() + ".limit(");
final String offset = getStringOffset(method, null);
if ( offset != null)
writer.print(offset + " + ");
if ( return_annotation.forceMaxLength() )
writer.print(return_annotation.maxLength());
else
writer.print(return_annotation.value() + "_length.get(0)");
writer.println(");");
writer.println("\t\treturn APIUtils.getString(" + return_annotation.value() + ");");
} else {
writer.print("\t\treturn " + return_annotation.value() + ".get(0)");
if ( "Boolean".equals(return_type) )
writer.print(" == 1");
writer.println(";");
}
}
}