/* * 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.opengl; import org.lwjgl.util.generator.*; import java.io.PrintWriter; import java.util.Arrays; import java.util.EnumSet; import java.util.Iterator; import java.util.List; import javax.annotation.processing.*; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; /** * Generator visitor for the context capabilities generator tool * * @author elias_naur * @version $Revision: 3355 $ * $Id: ContextCapabilitiesGenerator.java 3355 2010-05-27 22:56:29Z spasi $ */ public final class GLCapabilitiesGenerator { 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.append("public final class " + Utils.CONTEXT_CAPS_CLASS_NAME + " {\n"); writer.append("\tstatic final boolean DEBUG = ").append(Boolean.toString(generate_error_checks)).append(";\n"); writer.append("\tfinal APIUtil util = new APIUtil();\n"); writer.append("\tfinal StateTracker tracker = new StateTracker();\n\n"); if ( !context_specific ) { writer.append("\tprivate static boolean " + STUBS_LOADED_NAME + " = false;\n"); } } public static void generateInitializerPrologue(PrintWriter writer) { writer.append("\t" + Utils.CONTEXT_CAPS_CLASS_NAME + "(boolean forwardCompatible) throws LWJGLException {\n"); writer.append("\t\tSet " + CACHED_EXTS_VAR_NAME + " = " + ALL_INIT_METHOD_NAME + "(forwardCompatible);\n"); } private static PrintWriter translateFieldName(PrintWriter writer, String interface_name) { return writer.append(interface_name.startsWith("GL") ? CORE_PREFIX : EXTENSION_PREFIX) .append(interface_name); } public static void generateSuperClassAdds(PrintWriter writer, TypeElement d, ProcessingEnvironment env) { List super_interfaces = d.getInterfaces(); if ( super_interfaces.size() > 1 ) throw new RuntimeException(d + " extends more than one other interface"); if ( super_interfaces.size() == 1 ) { TypeMirror super_interface = super_interfaces.iterator().next(); writer.append("\t\tif (" + CACHED_EXTS_VAR_NAME + ".contains(\""); translateFieldName(writer, d.getSimpleName().toString()).append("\"))\n" + "\t\t\t"); generateAddExtension(writer, env.getElementUtils().getTypeElement(super_interface.toString())); } } public static void generateInitializer(PrintWriter writer, TypeElement d, ProcessingEnvironment env) { String non_translated_field_name = d.getSimpleName().toString(); translateFieldName(writer.append("\t\tthis."), non_translated_field_name).append(" = "); writer.append(CACHED_EXTS_VAR_NAME + ".contains(\""); translateFieldName(writer, non_translated_field_name).append("\")"); List super_interfaces = d.getInterfaces(); if ( super_interfaces.size() > 1 ) throw new RuntimeException(d + " extends more than one other interface"); if ( super_interfaces.size() == 1 ) { TypeMirror super_interface = super_interfaces.iterator().next(); writer.append("\n\t\t\t&& " + CACHED_EXTS_VAR_NAME + ".contains(\""); translateFieldName(writer, env.getElementUtils().getTypeElement(super_interface.toString()).getSimpleName().toString()).append("\")"); } Alias alias_annotation = d.getAnnotation(Alias.class); if ( alias_annotation != null ) { writer.append("\n\t\t\t|| " + CACHED_EXTS_VAR_NAME + ".contains(\""); translateFieldName(writer, alias_annotation.value()).append("\")"); } writer.append(";\n"); } private static PrintWriter getAddressesInitializerName(PrintWriter writer, String class_name) { return writer.append(class_name).append(POINTER_INITIALIZER_POSTFIX); } public static void generateInitStubsPrologue(PrintWriter writer, boolean context_specific) { writer.append("\tprivate Set " + ALL_INIT_METHOD_NAME + "(boolean forwardCompatible) throws LWJGLException {\n"); // Load the basic pointers we need to detect OpenGL version and supported extensions. writer.append("\t\tglGetError = GLContext.getFunctionAddress(\"glGetError\");\n"); writer.append("\t\tglGetString = GLContext.getFunctionAddress(\"glGetString\");\n"); // Initialize GL11.glGetIntegerv and GL30.glGetStringi here, in case we have created an OpenGL 3.0 context. // (they will be used in GLContext.getSupportedExtensions) writer.append("\t\tglGetIntegerv = GLContext.getFunctionAddress(\"glGetIntegerv\");\n"); writer.append("\t\tglGetStringi = GLContext.getFunctionAddress(\"glGetStringi\");\n"); // Get the supported extensions set. writer.append("\t\tGLContext.setCapabilities(this);\n"); writer.append("\t\tSet " + CACHED_EXTS_VAR_NAME + " = new HashSet(256);\n"); writer.append("\t\tint " + PROFILE_MASK_VAR_NAME + " = GLContext.getSupportedExtensions(" + CACHED_EXTS_VAR_NAME + ");\n"); // Force forward compatible mode when OpenGL version is 3.1 or higher and ARB_compatibility is not available. writer.append("\t\tif (" + CACHED_EXTS_VAR_NAME + ".contains(\"OpenGL31\") && !(" + CACHED_EXTS_VAR_NAME + ".contains(\"GL_ARB_compatibility\") || (" + PROFILE_MASK_VAR_NAME + " & GL32.GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0)) {\n"); writer.append("\t\t\tforwardCompatible = true;\n"); writer.append("\t\t\tLWJGLUtil.logger().log(() -> \"Forcing forwardCompatible=true because OpenGL version is 3.1 or higher AND ARB_compatibility is not available OR " + PROFILE_MASK_VAR_NAME + " has GL32.GL_CONTEXT_COMPATIBILITY_PROFILE_BIT set.\");\n"); writer.append("\t\t}\n"); if ( !context_specific ) { writer.append("\t\tif (" + STUBS_LOADED_NAME + ")\n"); writer.append("\t\t\treturn GLContext.getSupportedExtensions();\n"); writer.append("\t\torg.lwjgl.opengl.GL11." + Utils.STUB_INITIALIZER_NAME + "();\n"); } else { writer.append("\t\tif (!"); getAddressesInitializerName(writer, "GL11").append("(forwardCompatible))\n" + "\t\t\tthrow new LWJGLException(\"GL11 not supported\");\n"); } } public static void generateInitStubsEpilogue(PrintWriter writer, boolean context_specific) { if ( !context_specific ) { writer.append("\t\t" + STUBS_LOADED_NAME + " = true;\n"); } writer.append("\t\treturn " + CACHED_EXTS_VAR_NAME + ";\n"); writer.append("\t}\n"); } public static void generateUnloadStubs(ProcessingEnvironment env, PrintWriter writer, TypeElement d) { if ( Utils.getMethods(d).size() > 0 ) { writer.append("\t\tGLContext.resetNativeStubs(").append(Utils.getSimpleClassName(d)).append(".class);\n"); } } public static void generateInitStubs(ProcessingEnvironment env, PrintWriter writer, TypeElement d, boolean context_specific) { if ( Utils.getMethods(d).size() > 0 ) { if ( context_specific ) { final Alias alias_annotation = d.getAnnotation(Alias.class); if ( d.getAnnotation(ForceInit.class) != null ) { writer.append("\t\t" + CACHED_EXTS_VAR_NAME + ".add(\""); translateFieldName(writer, d.getSimpleName().toString()).append("\");\n"); } writer.append("\t\tif ("); if ( alias_annotation != null ) { writer.append('('); } writer.append(CACHED_EXTS_VAR_NAME + ".contains(\""); translateFieldName(writer, d.getSimpleName().toString()).append("\")"); if ( alias_annotation != null ) { writer.append(" || " + CACHED_EXTS_VAR_NAME + ".contains(\""); translateFieldName(writer, alias_annotation.value()).append("\"))"); } writer.append(" && !"); getAddressesInitializerName(writer, d.getSimpleName().toString()).append('('); if ( d.getAnnotation(DeprecatedGL.class) != null ) { writer.append("forwardCompatible"); } if ( d.getAnnotation(Dependent.class) != null ) { if ( d.getAnnotation(DeprecatedGL.class) != null ) { writer.append(","); } writer.append(CACHED_EXTS_VAR_NAME); } if ( alias_annotation != null ) { writer.append(")) {\n" + "\t\t\tremove(" + CACHED_EXTS_VAR_NAME + ", \""); translateFieldName(writer, alias_annotation.value()).append("\");\n"); } else { writer.append("))\n"); } writer.append("\t\t\tremove(" + CACHED_EXTS_VAR_NAME + ", \""); translateFieldName(writer, d.getSimpleName().toString()).append("\");\n"); if ( alias_annotation != null ) { writer.append("\t\t}\n"); } } else { writer.append("\t\tGLContext." + Utils.STUB_INITIALIZER_NAME + '(').append(Utils.getSimpleClassName(d)); writer.append(".class, " + CACHED_EXTS_VAR_NAME + ", \""); translateFieldName(writer, d.getSimpleName().toString()).append("\");\n"); } } } private static void generateAddExtension(PrintWriter writer, TypeElement d) { writer.append(CACHED_EXTS_VAR_NAME + ".add(\""); translateFieldName(writer, d.getSimpleName().toString()).append("\");\n"); } public static void generateAddressesInitializers(ProcessingEnvironment env, PrintWriter writer, TypeElement d) { Iterator methods = Utils.getMethods(d).iterator(); if (!methods.hasNext()) return; writer.append("\tprivate boolean "); getAddressesInitializerName(writer, d.getSimpleName().toString()).append('('); boolean optional; boolean deprecated = d.getAnnotation(DeprecatedGL.class) != null; Dependent dependent = d.getAnnotation(Dependent.class); if (deprecated) { writer.append("boolean forwardCompatible"); } if (dependent != null) { if (deprecated) { writer.append(','); } writer.append("Set " + CACHED_EXTS_VAR_NAME); } Alias alias_annotation = d.getAnnotation(Alias.class); boolean aliased = alias_annotation != null && alias_annotation.postfix().length() > 0; writer.append(") {\n" + "\t\treturn \n"); boolean first = true; while ( methods.hasNext() ) { ExecutableElement method = methods.next(); if ( method.getAnnotation(Alternate.class) != null ) continue; if (!first) { writer.append(" &\n"); } else { first = false; } optional = method.getAnnotation(Optional.class) != null; deprecated = method.getAnnotation(DeprecatedGL.class) != null; dependent = method.getAnnotation(Dependent.class); writer.append("\t\t\t("); if (optional) { writer.append('('); } if (deprecated) { writer.append("forwardCompatible || "); } if (dependent != null) { if (dependent.value().indexOf(',') == -1) writer.append("!" + CACHED_EXTS_VAR_NAME + ".contains(\"").append(dependent.value()).append("\") || "); else { writer.append("!(false"); for (String extension : dependent.value().split(",")) { writer.append(" || " + CACHED_EXTS_VAR_NAME + ".contains(\"").append(extension).append("\")"); } writer.append(") || "); } } if (deprecated || dependent != null) { writer.append('('); } writer.append(Utils.getFunctionAddressName(d, method)).append(" = "); PlatformDependent platform_dependent = method.getAnnotation(PlatformDependent.class); if (platform_dependent != null) { EnumSet platform_set = EnumSet.copyOf(Arrays.asList(platform_dependent.value())); writer.append("GLContext.getPlatformSpecificFunctionAddress(\"").append(Platform.ALL.getPrefix()).append("\", " + "new String[]{"); Iterator platforms = platform_set.iterator(); while ( platforms.hasNext() ) { writer.append("\"").append(platforms.next().getOSPrefix()).append("\""); if (platforms.hasNext()) { writer.append(", "); } } writer.append("}, new String[]{"); platforms = platform_set.iterator(); while (platforms.hasNext()) { writer.append("\"").append(platforms.next().getPrefix()).append("\""); if (platforms.hasNext()) { writer.append(", "); } } writer.append("}, "); } else if (aliased) { writer.append("GLContext.getFunctionAddress(new String[] {\"").append(method.getSimpleName()).append("\",\"").append(method.getSimpleName()).append(alias_annotation.postfix()).append("\"})) != 0"); } else { writer.append("GLContext.getFunctionAddress("); } if (!aliased) { writer.append("\"").append(method.getSimpleName()).append("\")) != 0"); } if (deprecated || dependent != null) { writer.append(')'); } if (optional) { writer.append(" || true)"); } } writer.append(";\n" + "\t}\n"); } public static void generateSymbolAddresses(ProcessingEnvironment env, PrintWriter writer, TypeElement d) { boolean first = true; for (final ExecutableElement method : Utils.getMethods(d)) { if (method.getAnnotation(Alternate.class) != null || method.getAnnotation(Reuse.class) != null) continue; if (first) { writer.append("\t// ").append(d.getSimpleName()).append('\n'); first = false; } writer.append("\tlong ").append(Utils.getFunctionAddressName(d, method)).append(";\n"); } } public static void generateField(PrintWriter writer, TypeElement d) { writer.append("\tpublic final boolean "); translateFieldName(writer, d.getSimpleName().toString()).append(";\n"); } }