Added PixelFormat support for framebuffer CSAA (NV_multisample_coverage, WGL & GLX only).

Added support for AMD_name_gen_delete and AMD_debug_output. The AMDDebugOutputCallback class enables query-less message handling.
Added support for extension aliases.
This commit is contained in:
Ioannis Tsakpinis 2010-05-27 22:56:29 +00:00
parent a3db874472
commit 21b3c3d818
30 changed files with 781 additions and 84 deletions

View file

@ -0,0 +1,162 @@
/*
* 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.opengl;
/**
* Instances of this class are needed to use the callback functionality of the AMD_debug_output extension.
* A debug context must be current before creating instances of this class. Users of this class may provide
* implementations of the {@code Handler} interface to receive notifications. The same {@code Handler}
* instance may be used by different contexts but it is not recommended. Handler notifications are synchronized.
*
* @author Spasi
*/
public final class AMDDebugOutputCallback implements PointerWrapper {
/** Severity levels. */
private static final int GL_DEBUG_SEVERITY_HIGH_AMD = 0x9146,
GL_DEBUG_SEVERITY_MEDIUM_AMD = 0x9147,
GL_DEBUG_SEVERITY_LOW_AMD = 0x9148;
/** Categories */
private static final int GL_DEBUG_CATEGORY_API_ERROR_AMD = 0x9149,
GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD = 0x914A,
GL_DEBUG_CATEGORY_DEPRECATION_AMD = 0x914B,
GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD = 0x914C,
GL_DEBUG_CATEGORY_PERFORMANCE_AMD = 0x914D,
GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD = 0x914E,
GL_DEBUG_CATEGORY_APPLICATION_AMD = 0x914F,
GL_DEBUG_CATEGORY_OTHER_AMD = 0x9150;
private final long pointer;
/**
* Creates a AMDDebugOutputCallback with a default callback handler.
* The default handler will simply print the message on System.err.
*/
public AMDDebugOutputCallback() {
this(new Handler() {
public void handleMessage(final int id, final int category, final int severity, final String message) {
System.err.println("[LWJGL] AMD_debug_output message");
System.err.println("\tID: " + id);
String description;
switch ( category ) {
case GL_DEBUG_CATEGORY_API_ERROR_AMD:
description = "API ERROR";
break;
case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD:
description = "WINDOW SYSTEM";
break;
case GL_DEBUG_CATEGORY_DEPRECATION_AMD:
description = "DEPRECATION";
break;
case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD:
description = "UNDEFINED BEHAVIOR";
break;
case GL_DEBUG_CATEGORY_PERFORMANCE_AMD:
description = "PERFORMANCE";
break;
case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD:
description = "SHADER COMPILER";
break;
case GL_DEBUG_CATEGORY_APPLICATION_AMD:
description = "APPLICATION";
break;
case GL_DEBUG_CATEGORY_OTHER_AMD:
description = "OTHER";
break;
default:
description = "Unknown (" + Integer.toHexString(category) + ")";
}
System.err.println("\tCategory: " + description);
switch ( severity ) {
case GL_DEBUG_SEVERITY_HIGH_AMD:
description = "HIGH";
break;
case GL_DEBUG_SEVERITY_MEDIUM_AMD:
description = "MEDIUM";
break;
case GL_DEBUG_SEVERITY_LOW_AMD:
description = "LOW";
break;
default:
description = "Unknown (" + Integer.toHexString(category) + ")";
}
System.err.println("\tSeverity: " + description);
System.err.println("\tMessage: " + message);
}
});
}
/**
* Creates a AMDDebugOutputCallback with the specified callback handlers.
* The handler's {@code handleMessage} method will be called whenever
* debug output is generated by the GL.
*
* @param handler the callback handler
*/
public AMDDebugOutputCallback(final Handler handler) {
try {
// We have to call registerHandler reflectively because we need this class to compile before we run the Generator.
// The registerHandler method depends on org.lwjgl.opengl.Context, if we touched that we would need to compile
// the whole library (which is not possible).
Class.forName("org.lwjgl.opengl.AMDDebugOutputUtil").getMethod("registerHandler", new Class[] { Handler.class }).invoke(null, new Object[] { handler });
} catch (Exception e) {
throw new RuntimeException(e.getCause() != null ? e.getCause() : e);
}
this.pointer = getFunctionPointer();
}
public long getPointer() {
return pointer;
}
private static native long getFunctionPointer();
/** Implementations of this interface can be used to receive AMD_debug_output notifications. */
public interface Handler {
/**
* This method will be called when an AMD_debug_output message is generated.
*
* @param id the message ID
* @param category the message category
* @param severity the message severity
* @param message the string representation of the message.
*/
void handleMessage(int id, int category, int severity, String message);
}
}

View file

@ -0,0 +1,59 @@
package org.lwjgl.opengl;
import org.lwjgl.opengl.AMDDebugOutputCallback.Handler;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.WeakHashMap;
/**
* This class handles AMDDebugOutputCallback.Handler registration and notification.
* We could have put this in AMDDebugOutputCallback, but we need to compile it for
* the generator. Registration is done reflectively in the AMDDebugOutputCallback
* constructor.
*
* @author Spasi
*/
final class AMDDebugOutputUtil {
private static final Map handlers = new WeakHashMap();
private AMDDebugOutputUtil() {}
public static void registerHandler(final Handler handler) {
final Context ctx = Context.getCurrentContext();
if ( ctx == null )
throw new IllegalStateException("No context is current.");
if ( !ctx.getContextAttribs().isDebug() )
throw new IllegalStateException("The current context is not a debug context.");
if ( !GLContext.getCapabilities().GL_AMD_debug_output )
throw new IllegalStateException("AMD_debug_output is not supported.");
handlers.put(ctx, handler);
}
/**
* This method is called by native code. If finds the callback handler associated
* with the current Thread and calls its {@code handleMessage} method.
*
* @param id the message ID
* @param category the message category
* @param severity the message severity
* @param message the string representation of the message.
* @param userParam the user-specified data specified in glDebugMessageCallbackAMD. For the current implementation this is always null and we ignore it.
*/
private static void messageCallback(final int id, final int category, final int severity, final String message, final ByteBuffer userParam) {
synchronized ( GlobalLock.lock ) {
final Context ctx = Context.getCurrentContext();
if ( ctx == null )
return;
final Handler handler = (Handler)handlers.get(ctx);
if ( handler != null )
handler.handleMessage(id, category, severity, message);
}
}
}

View file

@ -5,7 +5,6 @@ import org.lwjgl.LWJGLUtil;
/**
* @author Spasi
* @since 22 Áðñ 2010
*/
abstract class AbstractDrawable implements DrawableLWJGL {
@ -79,4 +78,4 @@ abstract class AbstractDrawable implements DrawableLWJGL {
throw new IllegalStateException("The Drawable has no context available.");
}
}
}

View file

@ -4,7 +4,6 @@ import org.lwjgl.LWJGLException;
/**
* @author Spasi
* @since 23 Áðñ 2010
*/
interface DrawableLWJGL extends Drawable {
@ -22,4 +21,4 @@ interface DrawableLWJGL extends Drawable {
*/
Context createSharedContext() throws LWJGLException;
}
}

View file

@ -169,6 +169,22 @@ public final class GLContext {
return 0;
}
/**
* Helper method to get a pointer to a named function with aliases in the OpenGL library.
*
* @param aliases the function name aliases.
*
* @return the function pointer address
*/
static long getFunctionAddress(String[] aliases) {
for ( int i = 0; i < aliases.length; i++ ) {
long address = getFunctionAddress(aliases[i]);
if ( address != 0 )
return address;
}
return 0;
}
/** Helper method to get a pointer to a named function in the OpenGL library */
static native long getFunctionAddress(String name);

View file

@ -66,6 +66,14 @@ public final class PixelFormat {
* 0 means that anti-aliasing is disabled.
*/
private int samples;
/**
* The number of COLOR_SAMPLES_NV to use for Coverage Sample Anti-aliasing (CSAA).
* When this number is greater than 0, the {@code samples} property will be treated
* as if it were the COVERAGE_SAMPLES_NV property.
* <p/>
* This property is currently a no-op for the MacOS implementation.
*/
private int colorSamples;
/** The number of auxiliary buffers */
private int num_aux_buffers;
/** The number of bits per pixel in the accumulation buffer */
@ -76,9 +84,15 @@ public final class PixelFormat {
private boolean stereo;
/** Whether this format specifies a floating point format */
private boolean floating_point;
/** Whether this format specifies a packed floating point format (32 bit unsigned - R11F_G11F_B10F) */
/**
* Whether this format specifies a packed floating point format (32 bit unsigned - R11F_G11F_B10F)
* This property is currently a no-op for the MacOS implementation.
*/
private boolean floating_point_packed;
/** Whether this format specifies an sRGB format */
/**
* Whether this format specifies an sRGB format
* This property is currently a no-op for the MacOS implementation.
*/
private boolean sRGB;
/**
@ -132,6 +146,7 @@ public final class PixelFormat {
this.stencil = pf.stencil;
this.samples = pf.samples;
this.colorSamples = pf.colorSamples;
this.num_aux_buffers = pf.num_aux_buffers;
@ -245,6 +260,38 @@ public final class PixelFormat {
return pf;
}
/**
* Returns a new PixelFormat object with the same properties as this PixelFormat and the new color samples values.
* A value greater than 0 is valid only if the {@code samples} property is also greater than 0. Additionally, the
* color samples value needs to be lower than or equal to the {@code samples} property.
*
* @param colorSamples the new color samples value.
*
* @return the new PixelFormat
*/
public PixelFormat withCoverageSamples(final int colorSamples) {
return withCoverageSamples(colorSamples, samples);
}
/**
* Returns a new PixelFormat object with the same properties as this PixelFormat and the new color samples
* and coverage samples values.
*
* @param colorSamples the new color samples value. This value must be lower than or equal to the coverage samples value.
* @param coverageSamples the new coverage samples value.
*
* @return the new PixelFormat
*/
public PixelFormat withCoverageSamples(final int colorSamples, final int coverageSamples) {
if ( coverageSamples < 0 || colorSamples < 0 || (coverageSamples == 0 && 0 < colorSamples) || coverageSamples < colorSamples )
throw new IllegalArgumentException("Invalid number of coverage samples specified: " + coverageSamples + " - " + colorSamples);
final PixelFormat pf = new PixelFormat(this);
pf.samples = coverageSamples;
pf.colorSamples = colorSamples;
return pf;
}
public int getAuxBuffers() {
return num_aux_buffers;
}

View file

@ -35,7 +35,6 @@ import org.lwjgl.LWJGLException;
/**
* @author Spasi
* @since 20 Áðñ 2010
*/
/**
@ -55,4 +54,4 @@ public final class SharedDrawable extends AbstractDrawable {
throw new UnsupportedOperationException();
}
}
}

View file

@ -148,7 +148,7 @@ public final class VersionTest {
boolean success = false;
boolean check;
if ( majorInput < 3 || minorInput == 0 ) {
if ( majorInput < 3 || (majorInput == 3 && minorInput == 0) ) {
System.out.println("\nA version less than or equal to 3.0 is requested, the context\n" +
"returned may implement any of the following versions:");
@ -252,4 +252,4 @@ public final class VersionTest {
System.exit(-1);
}
}
}

View file

@ -0,0 +1,54 @@
/*
* 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 can be used for extensions that have aliases
* with the exact same functionality.
* <p/>
* This is currently only implemented for context-specific functionality.
*
* @author Spasi <spasi@users.sourceforge.net>
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface Alias {
/** The aliased extension name. */
String value();
/** The function name postfix for the aliased version. (optional) */
String postfix() default "";
}

View file

@ -49,4 +49,5 @@ import java.lang.annotation.ElementType;
public @interface AutoSize {
String value(); // The name of the Buffer parameter
String expression() default ""; // This value is added after the argument
boolean canBeNull() default false; // When this is true and the Buffer parameter is null, 0 will be used.
}

View file

@ -51,13 +51,13 @@ import com.sun.mirror.type.InterfaceType;
*/
public class ContextCapabilitiesGenerator {
private final static String STUBS_LOADED_NAME = "loaded_stubs";
private final static String ALL_INIT_METHOD_NAME = "initAllStubs";
private final static String POINTER_INITIALIZER_POSTFIX = "_initNativeFunctionAddresses";
private final static String CACHED_EXTS_VAR_NAME = "supported_extensions";
private final static String PROFILE_MASK_VAR_NAME = "profileMask";
private final static String EXTENSION_PREFIX = "GL_";
private final static String CORE_PREFIX = "Open";
private static final String STUBS_LOADED_NAME = "loaded_stubs";
private static final String ALL_INIT_METHOD_NAME = "initAllStubs";
private static final String POINTER_INITIALIZER_POSTFIX = "_initNativeFunctionAddresses";
private static final String CACHED_EXTS_VAR_NAME = "supported_extensions";
private static final String PROFILE_MASK_VAR_NAME = "profileMask";
private static final String EXTENSION_PREFIX = "GL_";
private static final String CORE_PREFIX = "Open";
public static void generateClassPrologue(PrintWriter writer, boolean context_specific, boolean generate_error_checks) {
writer.println("public class " + Utils.CONTEXT_CAPS_CLASS_NAME + " {");
@ -108,6 +108,12 @@ public class ContextCapabilitiesGenerator {
writer.print("\t\t\t&& " + CACHED_EXTS_VAR_NAME + ".contains(\"");
writer.print(translateFieldName(super_interface.getDeclaration().getSimpleName()) + "\")");
}
Alias alias_annotation = d.getAnnotation(Alias.class);
if ( alias_annotation != null ) {
writer.println();
writer.print("\t\t\t|| " + CACHED_EXTS_VAR_NAME + ".contains(\"");
writer.print(translateFieldName(alias_annotation.value()) + "\")");
}
writer.println(";");
}
@ -164,10 +170,19 @@ public class ContextCapabilitiesGenerator {
public static void generateInitStubs(PrintWriter writer, InterfaceDeclaration d, boolean context_specific) {
if ( d.getMethods().size() > 0 ) {
if ( context_specific ) {
final Alias alias_annotation = d.getAnnotation(Alias.class);
if ( d.getAnnotation(ForceInit.class) != null )
writer.println("\t\t" + CACHED_EXTS_VAR_NAME + ".add(\"" + translateFieldName(d.getSimpleName()) + "\");");
writer.print("\t\tif (" + CACHED_EXTS_VAR_NAME + ".contains(\"");
writer.print("\t\tif (");
if ( alias_annotation != null )
writer.print("(");
writer.print(CACHED_EXTS_VAR_NAME + ".contains(\"");
writer.print(translateFieldName(d.getSimpleName()) + "\")");
if ( alias_annotation != null ) {
writer.print(" || " + CACHED_EXTS_VAR_NAME + ".contains(\"");
writer.print(translateFieldName(alias_annotation.value()) + "\"))");
}
writer.print(" && !" + getAddressesInitializerName(d.getSimpleName()) + "(");
if ( d.getAnnotation(DeprecatedGL.class) != null )
writer.print("forwardCompatible");
@ -176,10 +191,16 @@ public class ContextCapabilitiesGenerator {
writer.print(",");
writer.print("supported_extensions");
}
writer.println("))");
//writer.print("\t\t\t" + CACHED_EXTS_VAR_NAME + ".remove(\"");
if ( alias_annotation != null ) {
writer.println(")) {");
writer.print("\t\t\tremove(" + CACHED_EXTS_VAR_NAME + ", \"");
writer.println(translateFieldName(alias_annotation.value()) + "\");");
} else
writer.println("))");
writer.print("\t\t\tremove(" + CACHED_EXTS_VAR_NAME + ", \"");
writer.println(translateFieldName(d.getSimpleName()) + "\");");
if ( alias_annotation != null )
writer.println("\t\t}");
} else {
writer.print("\t\tGLContext." + Utils.STUB_INITIALIZER_NAME + "(" + Utils.getSimpleClassName(d));
writer.println(".class, " + CACHED_EXTS_VAR_NAME + ", \"" + translateFieldName(d.getSimpleName()) + "\");");
@ -210,6 +231,9 @@ public class ContextCapabilitiesGenerator {
writer.print("Set supported_extensions");
}
Alias alias_annotation = d.getAnnotation(Alias.class);
boolean aliased = alias_annotation != null && alias_annotation.postfix().length() > 0;
writer.println(") {");
writer.println("\t\treturn ");
@ -266,9 +290,12 @@ public class ContextCapabilitiesGenerator {
writer.print(", ");
}
writer.print("}, ");
} else if ( aliased ) {
writer.print("GLContext.getFunctionAddress(new String[] {\"" + method.getSimpleName() + "\",\"" + method.getSimpleName() + alias_annotation.postfix() + "\"})) != 0");
} else
writer.print("GLContext.getFunctionAddress(");
writer.print("\"" + method.getSimpleName() + "\")) != 0");
if ( !aliased )
writer.print("\"" + method.getSimpleName() + "\")) != 0");
if ( deprecated || dependent != null )
writer.print(')');
if ( optional )

View file

@ -32,70 +32,90 @@
package org.lwjgl.util.generator;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.*;
import java.io.PrintWriter;
import java.util.Collection;
import java.io.*;
import java.util.*;
import com.sun.mirror.declaration.FieldDeclaration;
import com.sun.mirror.declaration.Modifier;
import com.sun.mirror.type.PrimitiveType;
import com.sun.mirror.type.TypeMirror;
public class FieldsGenerator {
private static void validateField(FieldDeclaration field) {
// Check if field is "public static final"
Collection<Modifier> modifiers = field.getModifiers();
if (modifiers.size() != 3
|| !modifiers.contains(Modifier.PUBLIC)
|| !modifiers.contains(Modifier.STATIC)
|| !modifiers.contains(Modifier.FINAL)) {
throw new RuntimeException("Field " + field.getSimpleName() + " is not declared public static final");
}
// Check if field is "public static final"
Collection<Modifier> modifiers = field.getModifiers();
if ( modifiers.size() != 3
|| !modifiers.contains(Modifier.PUBLIC)
|| !modifiers.contains(Modifier.STATIC)
|| !modifiers.contains(Modifier.FINAL) ) {
throw new RuntimeException("Field " + field.getSimpleName() + " is not declared public static final");
}
// Check suported types (int, long, float, String)
TypeMirror field_type = field.getType();
if (field_type instanceof PrimitiveType) {
PrimitiveType field_type_prim = (PrimitiveType) field_type;
PrimitiveType.Kind field_kind = field_type_prim.getKind();
if (field_kind != PrimitiveType.Kind.INT
&& field_kind != PrimitiveType.Kind.LONG
&& field_kind != PrimitiveType.Kind.FLOAT) {
throw new RuntimeException("Field " + field.getSimpleName() + " is not of type 'int', 'long' or 'float'");
}
} else if (field_type.toString().equals("java.lang.String")) {
} else {
throw new RuntimeException("Field " + field.getSimpleName() + " is not a primitive type or String");
}
// Check suported types (int, long, float, String)
TypeMirror field_type = field.getType();
if ( field_type instanceof PrimitiveType ) {
PrimitiveType field_type_prim = (PrimitiveType)field_type;
PrimitiveType.Kind field_kind = field_type_prim.getKind();
if ( field_kind != PrimitiveType.Kind.INT
&& field_kind != PrimitiveType.Kind.LONG
&& field_kind != PrimitiveType.Kind.FLOAT ) {
throw new RuntimeException("Field " + field.getSimpleName() + " is not of type 'int', 'long' or 'float'");
}
} else if ( "java.lang.String".equals(field_type.toString()) ) {
} else {
throw new RuntimeException("Field " + field.getSimpleName() + " is not a primitive type or String");
}
Object field_value = field.getConstantValue();
if (field_value == null) {
throw new RuntimeException("Field " + field.getSimpleName() + " has no initial value");
}
Object field_value = field.getConstantValue();
if ( field_value == null ) {
throw new RuntimeException("Field " + field.getSimpleName() + " has no initial value");
}
}
private static void generateField(PrintWriter writer, FieldDeclaration field) {
validateField(field);
private static void generateField(PrintWriter writer, FieldDeclaration field, FieldDeclaration prev_field) {
validateField(field);
Object value = field.getConstantValue();
String field_value_string;
Class field_value_class = value.getClass();
if (field_value_class.equals(Integer.class)) {
field_value_string = "0x" + Integer.toHexString((Integer) field.getConstantValue());
} else if (field_value_class.equals(Long.class)) {
field_value_string = "0x" + Long.toHexString((Long) field.getConstantValue()) + 'l';
} else if (field_value_class.equals(Float.class)) {
field_value_string = field.getConstantValue() + "f";
} else if (field_value_class.equals(String.class)) {
field_value_string = "\"" + field.getConstantValue() + "\"";
} else {
throw new RuntimeException("Field is of unexpected type. This means there is a bug in validateField().");
}
Object value = field.getConstantValue();
String field_value_string;
Class field_value_class = value.getClass();
if ( field_value_class.equals(Integer.class) ) {
field_value_string = "0x" + Integer.toHexString((Integer)field.getConstantValue()).toUpperCase();
} else if ( field_value_class.equals(Long.class) ) {
field_value_string = "0x" + Long.toHexString((Long)field.getConstantValue()).toUpperCase() + 'L';
} else if ( field_value_class.equals(Float.class) ) {
field_value_string = field.getConstantValue() + "f";
} else if ( field_value_class.equals(String.class) ) {
field_value_string = "\"" + field.getConstantValue() + "\"";
} else {
throw new RuntimeException("Field is of unexpected type. This means there is a bug in validateField().");
}
Utils.printDocComment(writer, field);
// Print field declaration
writer.println("\tpublic static final " + field.getType().toString() + " " + field.getSimpleName() + " = " + field_value_string + ";");
boolean hadDoc = prev_field != null && prev_field.getDocComment() != null;
boolean hasDoc = field.getDocComment() != null;
boolean newBatch = prev_field == null || !prev_field.getType().equals(field.getType()) || (!hadDoc && field.getDocComment() != null) || (hadDoc && hasDoc && !prev_field.getDocComment().equals(field.getDocComment()));
// Print field declaration
if ( newBatch ) {
if ( prev_field != null )
writer.println(";\n");
Utils.printDocComment(writer, field);
writer.print("\tpublic static final " + field.getType().toString() + " " + field.getSimpleName() + " = " + field_value_string);
} else
writer.print(",\n\t\t" + field.getSimpleName() + " = " + field_value_string);
}
public static void generateFields(PrintWriter writer, Collection<FieldDeclaration> fields) {
for (FieldDeclaration field : fields)
generateField(writer, field);
if ( 0 < fields.size() ) {
writer.println();
FieldDeclaration prev_field = null;
for ( FieldDeclaration field : fields ) {
generateField(writer, field, prev_field);
prev_field = field;
}
writer.println(";");
}
}
}

View file

@ -40,4 +40,5 @@ import java.lang.annotation.ElementType;
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface GLpointer {
String value(); // The native pointer type.
boolean canBeNull() default false; // Whether the pointer may be null.
}

View file

@ -201,12 +201,12 @@ public class GeneratorVisitor extends SimpleDeclarationVisitor {
java_writer.println();
if (is_final) {
// Write private constructor to avoid instantiation
java_writer.println("\tprivate " + Utils.getSimpleClassName(d) + "() {");
java_writer.println("\t}");
java_writer.println();
java_writer.println("\tprivate " + Utils.getSimpleClassName(d) + "() {}");
}
if (d.getMethods().size() > 0 && !context_specific)
if (d.getMethods().size() > 0 && !context_specific) {
java_writer.println();
java_writer.println("\tstatic native void " + Utils.STUB_INITIALIZER_NAME + "() throws LWJGLException;");
}
JavaMethodsGenerator.generateMethodsJava(env, type_map, java_writer, d, generate_error_checks, context_specific);
java_writer.println("}");
java_writer.close();

View file

@ -387,7 +387,10 @@ public class JavaMethodsGenerator {
String auto_parameter_name = auto_type_annotation.value();
ParameterDeclaration auto_target_param = Utils.findParameter(method, auto_parameter_name);
TypeInfo auto_target_type_info = typeinfos_instance.get(auto_target_param);
writer.print("(" + auto_parameter_name + ".remaining()");
if ( auto_type_annotation.canBeNull() )
writer.print("((" + auto_parameter_name + " == null ? 0 : " + auto_parameter_name + ".remaining())");
else
writer.print("(" + auto_parameter_name + ".remaining()");
// Shift the remaining if the target parameter is multityped and there's no AutoType to track type
boolean shift_remaining = !hasAnyParameterAutoTypeAnnotation(method, auto_target_param) && Utils.isParameterMultiTyped(auto_target_param);
if (shift_remaining) {
@ -446,8 +449,13 @@ public class JavaMethodsGenerator {
writer.print(offset == null ? "0" : offset);
} else
writer.print("0");
} else if ( param.getAnnotation(GLpointer.class) != null ) {
writer.print(".getPointer()");
} else {
GLpointer pointer_annotation = param.getAnnotation(GLpointer.class);
if ( pointer_annotation != null ) {
if ( pointer_annotation.canBeNull() )
writer.print(" == null ? 0 : " + param.getSimpleName());
writer.print(".getPointer()");
}
}
}
}