All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jogamp.gluegen.opengl.BuildComposablePipeline Maven / Gradle / Ivy

There is a newer version: 2.3.2
Show newest version
/*
 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
 * Copyright (c) 2010 JogAmp Community. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistribution 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 Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed or intended for use
 * in the design, construction, operation or maintenance of any nuclear
 * facility.
 * 
 * Sun gratefully acknowledges that this software was originally authored
 * and developed by Kenneth Bradley Russell and Christopher John Kline.
 */
package com.jogamp.gluegen.opengl;

import com.jogamp.gluegen.CodeGenUtils;
import com.jogamp.gluegen.JavaType;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class BuildComposablePipeline {

    public static final int GEN_DEBUG = 1 << 0; // default
    public static final int GEN_TRACE = 1 << 1; // default
    public static final int GEN_CUSTOM = 1 << 2;
    public static final int GEN_PROLOG_XOR_DOWNSTREAM = 1 << 3;
    int mode;
    private String outputDir;
    private String outputPackage;
    private String outputName;
    private Class classToComposeAround;
    private Class classPrologOpt;
    private Class classDownstream;
    // Only desktop OpenGL has immediate mode glBegin / glEnd
    private boolean hasImmediateMode;
    // Desktop OpenGL and GLES1 have GL_STACK_OVERFLOW and GL_STACK_UNDERFLOW errors
    private boolean hasStackOverflow;

    public static Class getClass(String name) {
        Class clazz = null;
        try {
            clazz = Class.forName(name);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Could not find class \"" + name + "\"", e);
        }
        return clazz;
    }

    public static Method getMethod(Class clazz, Method m) {
        Method res = null;
        try {
            res = clazz.getMethod(m.getName(), m.getParameterTypes());
        } catch (Exception e) {
        }
        return res;
    }

    public static void main(String[] args) {
        String classToComposeAroundName = args[0];
        Class classPrologOpt, classDownstream;
        Class classToComposeAround = getClass(classToComposeAroundName);

        String outputDir = args[1];
        String outputPackage, outputName;
        int mode;

        if (args.length > 2) {
            String outputClazzName = args[2];
            outputPackage = getPackageName(outputClazzName);
            outputName = getBaseClassName(outputClazzName);
            classPrologOpt = getClass(args[3]);
            classDownstream = getClass(args[4]);
            mode = GEN_CUSTOM;
            if (args.length > 5) {
                if (args[5].equals("prolog_xor_downstream")) {
                    mode |= GEN_PROLOG_XOR_DOWNSTREAM;
                }
            }
        } else {
            outputPackage = getPackageName(classToComposeAroundName);
            outputName = null; // TBD ..
            classPrologOpt = null;
            classDownstream = classToComposeAround;
            mode = GEN_DEBUG | GEN_TRACE;
        }

        BuildComposablePipeline composer =
                new BuildComposablePipeline(mode, outputDir, outputPackage, outputName, classToComposeAround, classPrologOpt, classDownstream);

        try {
            composer.emit();
        } catch (IOException e) {
            throw new RuntimeException(
                    "Error generating composable pipeline source files", e);
        }
    }

    protected BuildComposablePipeline(int mode, String outputDir, String outputPackage, String outputName,
            Class classToComposeAround, Class classPrologOpt, Class classDownstream) {
        this.mode = mode;
        this.outputDir = outputDir;
        this.outputPackage = outputPackage;
        this.outputName = outputName;
        this.classToComposeAround = classToComposeAround;
        this.classPrologOpt = classPrologOpt;
        this.classDownstream = classDownstream;

        if (!classToComposeAround.isInterface()) {
            throw new IllegalArgumentException(
                    classToComposeAround.getName() + " is not an interface class");
        }

        try {
            hasImmediateMode =
                    (classToComposeAround.getMethod("glBegin", new Class[]{Integer.TYPE}) != null);
        } catch (Exception e) {
        }

        try {
            hasStackOverflow =
                    (classToComposeAround.getField("GL_STACK_OVERFLOW") != null);
        } catch (Exception e) {
        }
    }

    /**
     * Emit the java source code for the classes that comprise the composable
     * pipeline.
     */
    public void emit() throws IOException {

        List publicMethodsRaw = Arrays.asList(classToComposeAround.getMethods());

        Set publicMethodsPlain = new HashSet();
        for (Iterator iter = publicMethodsRaw.iterator(); iter.hasNext();) {
            Method method = iter.next();
            // Don't hook methods which aren't real GL methods,
            // such as the synthetic "isGL2ES2" "getGL2ES2"
            String name = method.getName();
            boolean runHooks = name.startsWith("gl");
            if (!name.startsWith("getGL") && !name.startsWith("isGL") && !name.equals("toString")) {
                publicMethodsPlain.add(new PlainMethod(method, runHooks));
            }
        }

        if (0 != (mode & GEN_DEBUG)) {
            (new DebugPipeline(outputDir, outputPackage, classToComposeAround, classDownstream)).emit(publicMethodsPlain.iterator());
        }
        if (0 != (mode & GEN_TRACE)) {
            (new TracePipeline(outputDir, outputPackage, classToComposeAround, classDownstream)).emit(publicMethodsPlain.iterator());
        }
        if (0 != (mode & GEN_CUSTOM)) {
            (new CustomPipeline(mode, outputDir, outputPackage, outputName, classToComposeAround, classPrologOpt, classDownstream)).emit(publicMethodsPlain.iterator());
        }
    }

    public static String getPackageName(String clazzName) {
        int lastDot = clazzName.lastIndexOf('.');
        if (lastDot == -1) {
            // no package, class is at root level
            return null;
        }
        return clazzName.substring(0, lastDot);
    }

    public static String getBaseClassName(String clazzName) {
        int lastDot = clazzName.lastIndexOf('.');
        if (lastDot == -1) {
            // no package, class is at root level
            return clazzName;
        }
        return clazzName.substring(lastDot + 1);
    }

    //-------------------------------------------------------
    protected class PlainMethod {

        Method m;
        boolean runHooks;

        PlainMethod(Method m, boolean runHooks) {
            this.m = m;
            this.runHooks = runHooks;
        }

        public Method getWrappedMethod() {
            return m;
        }

        public boolean runHooks() {
            return runHooks;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof PlainMethod) {
                PlainMethod b = (PlainMethod) obj;
                boolean res =
                        m.getName().equals(b.m.getName())
                        && m.getModifiers() == b.m.getModifiers()
                        && m.getReturnType().equals(b.m.getReturnType())
                        && Arrays.equals(m.getParameterTypes(), b.m.getParameterTypes());
                return res;
            }
            return false;
        }

        @Override
        public int hashCode() {
            int hash = m.getName().hashCode() ^ m.getModifiers() ^ m.getReturnType().hashCode();
            Class[] args = m.getParameterTypes();
            for (int i = 0; i < args.length; i++) {
                hash ^= args[i].hashCode();
            }
            return hash;
        }

        @Override
        public String toString() {
            Class[] args = m.getParameterTypes();
            StringBuilder argsString = new StringBuilder();
            argsString.append("(");
            for (int i = 0; i < args.length; i++) {
                if (i > 0) {
                    argsString.append(", ");
                }
                argsString.append(args[i].getName());
            }
            argsString.append(")");
            return m.toString()
                    + "\n\tname: " + m.getName()
                    + "\n\tmods: " + m.getModifiers()
                    + "\n\tretu: " + m.getReturnType()
                    + "\n\targs[" + args.length + "]: " + argsString.toString();
        }
    }

    /**
     * Emits a Java source file that represents one element of the composable
     * pipeline.
     */
    protected abstract class PipelineEmitter {

        private File file;
        protected String basePackage;
        protected String baseName; // does not include package!
        protected String downstreamPackage;
        protected String downstreamName; // does not include package!
        protected String prologPackageOpt = null;
        protected String prologNameOpt = null; // does not include package!
        protected String outputDir;
        protected String outputPackage;
        protected Class baseInterfaceClass;
        protected Class prologClassOpt = null;
        protected Class downstreamClass;

        /**
         * @param outputDir the directory into which the pipeline classes will be
         * generated.
         * @param baseInterfaceClassName the full class name (including package,
         * e.g. "java.lang.String") of the interface that the pipeline wraps
         * @exception IllegalArgumentException if classToComposeAround is not an
         * interface.
         */
        PipelineEmitter(String outputDir, String outputPackage, Class baseInterfaceClass, Class prologClassOpt, Class downstreamClass) {
            this.outputDir = outputDir;
            this.outputPackage = outputPackage;
            this.baseInterfaceClass = baseInterfaceClass;
            this.prologClassOpt = prologClassOpt;
            this.downstreamClass = downstreamClass;

            basePackage = getPackageName(baseInterfaceClass.getName());
            baseName = getBaseClassName(baseInterfaceClass.getName());
            downstreamPackage = getPackageName(downstreamClass.getName());
            downstreamName = getBaseClassName(downstreamClass.getName());
            if (null != prologClassOpt) {
                prologPackageOpt = getPackageName(prologClassOpt.getName());
                prologNameOpt = getBaseClassName(prologClassOpt.getName());
            }
        }

        public void emit(Iterator methodsToWrap) throws IOException {
            String outputClassName = getOutputName();
            this.file = new File(outputDir + File.separatorChar + outputClassName + ".java");
            String parentDir = file.getParent();
            if (parentDir != null) {
                File pDirFile = new File(parentDir);
                pDirFile.mkdirs();
            }

            PrintWriter output = new PrintWriter(new BufferedWriter(new FileWriter(file)));

            List> baseInterfaces = Arrays.asList(baseInterfaceClass.getInterfaces());
            HashSet> clazzList = new HashSet>();
            clazzList.add(baseInterfaceClass);
            clazzList.addAll(baseInterfaces);
            int ifNamesNumber = clazzList.size();

            // keep original order ..
            clazzList.clear();
            String[] ifNames = new String[ifNamesNumber];
            {
                int i = 0;

                for (Iterator> iter = baseInterfaces.iterator(); iter.hasNext();) {
                    Class ifClass = iter.next();
                    if (!clazzList.contains(ifClass)) {
                        ifNames[i++] = ifClass.getName();
                        clazzList.add(ifClass);
                    }
                }

                if (null != baseInterfaceClass && !clazzList.contains(baseInterfaceClass)) {
                    ifNames[i++] = baseInterfaceClass.getName();
                    clazzList.add(baseInterfaceClass);
                }
            }

            clazzList.add(downstreamClass);
            if (null != prologClassOpt) {
                clazzList.add(prologClassOpt);
            }

            ArrayList imports = new ArrayList();
            imports.add("java.io.*");
            imports.add("javax.media.opengl.*");
            imports.add("com.jogamp.gluegen.runtime.*");
            imports.add(Buffer.class.getPackage().getName()+".*");
            for (Class clasS : clazzList) {
                imports.add(clasS.getName());
            }

            CodeGenUtils.emitJavaHeaders(output,
                    outputPackage,
                    outputClassName,
                    true,
                    imports,
                    new String[]{"public"},
                    ifNames,
                    null,
                    new CodeGenUtils.EmissionCallback() {
                        public void emit(PrintWriter w) {
                            emitClassDocComment(w);
                        }
                    });

            preMethodEmissionHook(output);

            constructorHook(output);

            emitGLIsMethods(output);
            emitGLGetMethods(output);

            while (methodsToWrap.hasNext()) {
                PlainMethod pm = methodsToWrap.next();
                Method m = pm.getWrappedMethod();
                emitMethodDocComment(output, m);
                emitSignature(output, m);
                emitBody(output, m, pm.runHooks());
            }

            postMethodEmissionHook(output);

            output.println();
            output.print("  private " + downstreamName + " " + getDownstreamObjectName() + ";");

            // end the class
            output.println();
            output.print("} // end class ");
            output.println(outputClassName);

            output.flush();
            output.close();

            System.out.println("wrote to file: " + file);
        }

        /** Get the name of the object through which API calls should be routed. */
        protected String getDownstreamObjectName() {
            return "downstream" + downstreamName;
        }

        /** Get the name of the object which shall be called as a prolog. */
        protected String getPrologObjectNameOpt() {
            if (null != prologNameOpt) {
                return "prolog" + prologNameOpt;
            }
            return null;
        }

        protected void emitMethodDocComment(PrintWriter output, Method m) {
        }

        protected void emitSignature(PrintWriter output, Method m) {
            output.print("  public ");
            output.print(' ');
            output.print(JavaType.createForClass(m.getReturnType()).getName());
            output.print(' ');
            output.print(m.getName());
            output.print('(');
            output.print(getArgListAsString(m, true, true));
            output.println(")");
        }

        protected void emitBody(PrintWriter output, Method m, boolean runHooks) {
            output.println("  {");
            output.print("    ");
            Class retType = m.getReturnType();

            boolean callPreDownstreamHook = runHooks && hasPreDownstreamCallHook(m);
            boolean callPostDownstreamHook = runHooks && hasPostDownstreamCallHook(m);
            boolean callDownstream = (null != getMethod(downstreamClass, m))
                    && !(0 != (GEN_PROLOG_XOR_DOWNSTREAM & getMode()) && callPreDownstreamHook);
            boolean hasResult = (retType != Void.TYPE);

            if (!callDownstream) {
                if (!emptyDownstreamAllowed()) {
                    throw new RuntimeException("Method " + m + " has no downstream (" + downstreamName + ")");
                }
            }

            if (!callPreDownstreamHook && !callPostDownstreamHook && !callDownstream) {
                if (!emptyMethodAllowed()) {
                    throw new RuntimeException("Method " + m + " is empty, no downstream (" + downstreamName + ") nor prolog (" + prologNameOpt + ").");
                } else {
                    output.print("    if(DEBUG) { System.out.println(\"WARNING: No prolog, no downstream, empty: \"+");
                    printFunctionCallString(output, m);
                    output.println("); } ");
                }
            }

            if (callPreDownstreamHook) {
                if (hasResult && !callDownstream) {
                    if (callPostDownstreamHook) {
                        output.print("    " + JavaType.createForClass(retType).getName());
                        output.print(" _res = ");
                    } else {
                        output.print("    return ");
                    }
                }
                preDownstreamCallHook(output, m);
            }

            if (callDownstream) {
                if (hasResult) {
                    if (callPostDownstreamHook) {
                        output.print("    " + JavaType.createForClass(retType).getName());
                        output.print(" _res = ");
                    } else {
                        output.print("    return ");
                    }
                }
                output.print(getDownstreamObjectName());
                output.print('.');
                output.print(m.getName());
                output.print('(');
                output.print(getArgListAsString(m, false, true));
                output.println(");");
            }

            if (callPostDownstreamHook) {
                postDownstreamCallHook(output, m);
            }

            if (hasResult && callDownstream && callPostDownstreamHook) {
                output.println("    return _res;");
            }
            output.println("  }");

        }

        protected String getArgListAsString(Method m, boolean includeArgTypes, boolean includeArgNames) {
            StringBuilder buf = new StringBuilder(256);
            if (!includeArgNames && !includeArgTypes) {
                throw new IllegalArgumentException(
                        "Cannot generate arglist without both arg types and arg names");
            }

            Class[] argTypes = m.getParameterTypes();
            for (int i = 0; i < argTypes.length; ++i) {
                if (includeArgTypes) {
                    buf.append(JavaType.createForClass(argTypes[i]).getName());
                    buf.append(' ');
                }

                if (includeArgNames) {
                    buf.append("arg");
                    buf.append(i);
                }
                if (i < argTypes.length - 1) {
                    buf.append(',');
                }
            }

            return buf.toString();
        }

        /** The name of the class around which this pipeline is being
         * composed. E.g., if this pipeline was constructed with
         * "java.util.Set" as the baseInterfaceClassName, then this method will
         * return "Set".
         */
        protected String getBaseInterfaceName() {
            return baseName;
        }

        /** Get the output name for this pipeline class. */
        protected abstract String getOutputName();

        /**
         * Called after the class headers have been generated, but before any
         * method wrappers have been generated.
         */
        protected void preMethodEmissionHook(PrintWriter output) {
            output.println("  public static final boolean DEBUG = jogamp.opengl.Debug.debug(\"" + getOutputName() + "\");");
        }

        /**
         * Emits the constructor for the pipeline; called after the preMethodEmissionHook.
         */
        protected abstract void constructorHook(PrintWriter output);

        /**
         * Called after the method wrappers have been generated, but before the
         * closing parenthesis of the class is emitted.
         */
        protected void postMethodEmissionHook(PrintWriter output) {
            output.println("  public String toString() {");
            output.println("    StringBuilder sb = new StringBuilder();");
            output.println("    sb.append(\"" + getOutputName() + " [ implementing " + baseInterfaceClass.getName() + ",\\n\\t\");");
            if (null != prologClassOpt) {
                output.println("    sb.append(\" prolog: \"+" + getPrologObjectNameOpt() + ".toString()+\",\\n\\t\");");
            }
            output.println("    sb.append(\" downstream: \"+" + getDownstreamObjectName() + ".toString()+\"\\n\\t]\");");
            output.println("    return sb.toString();");
            output.println("  }");
        }

        /**
         * Called before the pipeline routes the call to the downstream object.
         */
        protected abstract void preDownstreamCallHook(PrintWriter output, Method m);

        protected abstract boolean hasPreDownstreamCallHook(Method m);

        /**
         * Called after the pipeline has routed the call to the downstream object,
         * but before the calling function exits or returns a value.
         */
        protected abstract void postDownstreamCallHook(PrintWriter output, Method m);

        protected abstract boolean hasPostDownstreamCallHook(Method m);

        protected abstract int getMode();

        protected abstract boolean emptyMethodAllowed();

        protected abstract boolean emptyDownstreamAllowed();

        /** Emit a Javadoc comment for this pipeline class. */
        protected abstract void emitClassDocComment(PrintWriter output);

        /**
         * Emits one of the isGL* methods.
         */
        protected void emitGLIsMethod(PrintWriter output, String type) {
            output.println("  public boolean is" + type + "() {");
            Class clazz = BuildComposablePipeline.getClass("javax.media.opengl." + type);
            if (clazz.isAssignableFrom(baseInterfaceClass)) {
                output.println("    return true;");
            } else {
                output.println("    return false;");
            }
            output.println("  }");
        }

        /**
         * Emits all of the isGL* methods.
         */
        protected void emitGLIsMethods(PrintWriter output) {
            emitGLIsMethod(output, "GL");
            emitGLIsMethod(output, "GL4bc");
            emitGLIsMethod(output, "GL4");
            emitGLIsMethod(output, "GL3bc");
            emitGLIsMethod(output, "GL3");
            emitGLIsMethod(output, "GL2");
            emitGLIsMethod(output, "GLES1");
            emitGLIsMethod(output, "GLES2");
            emitGLIsMethod(output, "GL2ES1");
            emitGLIsMethod(output, "GL2ES2");
            emitGLIsMethod(output, "GL2GL3");
            output.println("  public boolean isGLES() {");
            output.println("    return isGLES2() || isGLES1();");
            output.println("  }");
            output.println("  public boolean isGLES2Compatible() {");
            output.println("    return " + getDownstreamObjectName() + ".isGLES2Compatible();");
            output.println("  }");
        }

        /**
         * Emits one of the getGL* methods.
         */
        protected void emitGLGetMethod(PrintWriter output, String type) {
            output.println("  public javax.media.opengl." + type + " get" + type + "() {");
            Class clazz = BuildComposablePipeline.getClass("javax.media.opengl." + type);
            if (clazz.isAssignableFrom(baseInterfaceClass)) {
                output.println("    return this;");
            } else {
                output.println("    throw new GLException(\"Not a " + type + " implementation\");");
            }
            output.println("  }");
        }

        /**
         * Emits all of the getGL* methods.
         */
        protected void emitGLGetMethods(PrintWriter output) {
            emitGLGetMethod(output, "GL");
            emitGLGetMethod(output, "GL4bc");
            emitGLGetMethod(output, "GL4");
            emitGLGetMethod(output, "GL3bc");
            emitGLGetMethod(output, "GL3");
            emitGLGetMethod(output, "GL2");
            emitGLGetMethod(output, "GLES1");
            emitGLGetMethod(output, "GLES2");
            emitGLGetMethod(output, "GL2ES1");
            emitGLGetMethod(output, "GL2ES2");
            emitGLGetMethod(output, "GL2GL3");
            output.println("  public GLProfile getGLProfile() {");
            output.println("    return " + getDownstreamObjectName() + ".getGLProfile();");
            output.println("  }");
        }
    } // end class PipelineEmitter

    //-------------------------------------------------------
    protected class CustomPipeline extends PipelineEmitter {

        String className;
        int mode;

        CustomPipeline(int mode, String outputDir, String outputPackage, String outputName, Class baseInterfaceClass, Class prologClassOpt, Class downstreamClass) {
            super(outputDir, outputPackage, baseInterfaceClass, prologClassOpt, downstreamClass);
            className = outputName;
            this.mode = mode;
        }

        protected String getOutputName() {
            return className;
        }

        protected int getMode() {
            return mode;
        }

        protected boolean emptyMethodAllowed() {
            return true;
        }

        protected boolean emptyDownstreamAllowed() {
            return true;
        }

        @Override
        protected void preMethodEmissionHook(PrintWriter output) {
            super.preMethodEmissionHook(output);
        }

        protected void constructorHook(PrintWriter output) {
            output.print("  public " + getOutputName() + "(");
            output.print(downstreamName + " " + getDownstreamObjectName());
            if (null != prologNameOpt) {
                output.println(", " + prologNameOpt + " " + getPrologObjectNameOpt() + ")");
            } else {
                output.println(")");
            }
            output.println("  {");
            output.println("    if (" + getDownstreamObjectName() + " == null) {");
            output.println("      throw new IllegalArgumentException(\"null " + getDownstreamObjectName() + "\");");
            output.println("    }");
            output.print("    this." + getDownstreamObjectName());
            output.println(" = " + getDownstreamObjectName() + ";");
            if (null != prologNameOpt) {
                output.print("    this." + getPrologObjectNameOpt());
                output.println(" = " + getPrologObjectNameOpt() + ";");
            }
            output.println("  }");
            output.println();
        }

        @Override
        protected void postMethodEmissionHook(PrintWriter output) {
            super.postMethodEmissionHook(output);
            if (null != prologNameOpt) {
                output.print("  private " + prologNameOpt + " " + getPrologObjectNameOpt() + ";");
            }
        }

        protected void emitClassDocComment(PrintWriter output) {
            output.println("/**");
            output.println(" * Composable pipeline {@link " + outputPackage + "." + outputName + "}, implementing the interface");
            output.println(" * {@link " + baseInterfaceClass.getName() + "}");
            output.println(" * 

"); output.println(" * Each method follows the call graph

    "); if (null != prologClassOpt) { output.println(" *
  • call prolog {@link " + prologClassOpt.getName() + "} if available"); } output.println(" *
  • call downstream {@link " + downstreamClass.getName() + "} if available"); if (null != prologClassOpt && 0 != (GEN_PROLOG_XOR_DOWNSTREAM & getMode())) { output.println(" * and if no call to {@link " + prologClassOpt.getName() + "} is made"); } output.println(" *

"); output.println(" * "); output.println(" *

    "); output.println(" *
  • Interface {@link " + baseInterfaceClass.getName() + "}"); if (null != prologClassOpt) { output.println(" *
  • Prolog {@link " + prologClassOpt.getName() + "}"); } output.println(" *
  • Downstream {@link " + downstreamClass.getName() + "}"); output.println(" *

"); output.println(" * Sample code which installs this pipeline:

"); output.println(" * "); output.println("
");
            if (null != prologNameOpt) {
                output.println("     GL gl = drawable.setGL( new " + className + "( drawable.getGL().getGL2ES2(), new " + prologNameOpt + "( drawable.getGL().getGL2ES2() ) ) );");
            } else {
                output.println("     GL gl = drawable.setGL( new " + className + "( drawable.getGL().getGL2ES2() ) );");
            }
            output.println("
"); output.println("*/"); } protected boolean hasPreDownstreamCallHook(Method m) { return null != getMethod(prologClassOpt, m); } protected void preDownstreamCallHook(PrintWriter output, Method m) { if (null != prologNameOpt) { output.print(getPrologObjectNameOpt()); output.print('.'); output.print(m.getName()); output.print('('); output.print(getArgListAsString(m, false, true)); output.println(");"); } } protected boolean hasPostDownstreamCallHook(Method m) { return false; } protected void postDownstreamCallHook(PrintWriter output, Method m) { } } // end class CustomPipeline protected class DebugPipeline extends PipelineEmitter { String className; DebugPipeline(String outputDir, String outputPackage, Class baseInterfaceClass, Class downstreamClass) { super(outputDir, outputPackage, baseInterfaceClass, null, downstreamClass); className = "Debug" + getBaseInterfaceName(); } protected String getOutputName() { return className; } protected int getMode() { return 0; } protected boolean emptyMethodAllowed() { return false; } protected boolean emptyDownstreamAllowed() { return false; } @Override protected void preMethodEmissionHook(PrintWriter output) { super.preMethodEmissionHook(output); } protected void constructorHook(PrintWriter output) { output.print(" public " + getOutputName() + "("); output.println(downstreamName + " " + getDownstreamObjectName() + ")"); output.println(" {"); output.println(" if (" + getDownstreamObjectName() + " == null) {"); output.println(" throw new IllegalArgumentException(\"null " + getDownstreamObjectName() + "\");"); output.println(" }"); output.print(" this." + getDownstreamObjectName()); output.println(" = " + getDownstreamObjectName() + ";"); if (null != prologNameOpt) { output.print(" this." + getPrologObjectNameOpt()); output.println(" = " + getPrologObjectNameOpt() + ";"); } output.println(" // Fetch GLContext object for better error checking (if possible)"); output.println(" _context = " + getDownstreamObjectName() + ".getContext();"); output.println(" }"); output.println(); } @Override protected void postMethodEmissionHook(PrintWriter output) { super.postMethodEmissionHook(output); output.println(" private void checkGLGetError(String caller)"); output.println(" {"); if (hasImmediateMode) { output.println(" if (insideBeginEndPair) {"); output.println(" return;"); output.println(" }"); output.println(); } output.println(" // Debug code to make sure the pipeline is working; leave commented out unless testing this class"); output.println(" //System.err.println(\"Checking for GL errors " + "after call to \" + caller);"); output.println(); output.println(" int err = " + getDownstreamObjectName() + ".glGetError();"); output.println(" if (err == GL_NO_ERROR) { return; }"); output.println(); output.println(" StringBuilder buf = new StringBuilder(Thread.currentThread()+"); output.println(" \" glGetError() returned the following error codes after a call to \" + caller + \": \");"); output.println(); output.println(" // Loop repeatedly to allow for distributed GL implementations,"); output.println(" // as detailed in the glGetError() specification"); output.println(" int recursionDepth = 10;"); output.println(" do {"); output.println(" switch (err) {"); output.println(" case GL_INVALID_ENUM: buf.append(\"GL_INVALID_ENUM \"); break;"); output.println(" case GL_INVALID_VALUE: buf.append(\"GL_INVALID_VALUE \"); break;"); output.println(" case GL_INVALID_OPERATION: buf.append(\"GL_INVALID_OPERATION \"); break;"); if (hasStackOverflow) { output.println(" case GL_STACK_OVERFLOW: buf.append(\"GL_STACK_OVERFLOW \"); break;"); output.println(" case GL_STACK_UNDERFLOW: buf.append(\"GL_STACK_UNDERFLOW \"); break;"); } output.println(" case GL_OUT_OF_MEMORY: buf.append(\"GL_OUT_OF_MEMORY \"); break;"); output.println(" case GL_NO_ERROR: throw new InternalError(\"Should not be treating GL_NO_ERROR as error\");"); output.println(" default: buf.append(\"Unknown glGetError() return value: \");"); output.println(" }"); output.println(" buf.append(\"( \" + err + \" 0x\"+Integer.toHexString(err).toUpperCase() + \"), \");"); output.println(" } while ((--recursionDepth >= 0) && (err = " + getDownstreamObjectName() + ".glGetError()) != GL_NO_ERROR);"); output.println(" throw new GLException(buf.toString());"); output.println(" }"); if (hasImmediateMode) { output.println(" /** True if the pipeline is inside a glBegin/glEnd pair.*/"); output.println(" private boolean insideBeginEndPair = false;"); output.println(); } output.println(" private void checkContext() {"); output.println(" GLContext currentContext = GLContext.getCurrent();"); output.println(" if (currentContext == null) {"); output.println(" throw new GLException(\"No OpenGL context is current on this thread\");"); output.println(" }"); output.println(" if ((_context != null) && (_context != currentContext)) {"); output.println(" throw new GLException(\"This GL object is being incorrectly used with a different GLContext than that which created it\");"); output.println(" }"); output.println(" }"); output.println(" private GLContext _context;"); } protected void emitClassDocComment(PrintWriter output) { output.println("/**

Composable pipeline which wraps an underlying {@link GL} implementation,"); output.println(" providing error checking after each OpenGL method call. If an error occurs,"); output.println(" causes a {@link GLException} to be thrown at exactly the point of failure."); output.println(" Sample code which installs this pipeline:

"); output.println(); output.println("
");
            output.println("     GL gl = drawable.setGL(new DebugGL(drawable.getGL()));");
            output.println("
"); output.println("*/"); } protected boolean hasPreDownstreamCallHook(Method m) { return true; } protected void preDownstreamCallHook(PrintWriter output, Method m) { output.println(" checkContext();"); } protected boolean hasPostDownstreamCallHook(Method m) { return true; } protected void postDownstreamCallHook(PrintWriter output, Method m) { if (m.getName().equals("glBegin")) { output.println(" insideBeginEndPair = true;"); output.println(" // NOTE: can't check glGetError(); it's not allowed inside glBegin/glEnd pair"); } else { if (m.getName().equals("glEnd")) { output.println(" insideBeginEndPair = false;"); } output.println(" String txt = new String(\"" + m.getName() + "(\" +"); Class[] params = m.getParameterTypes(); for (int i = 0; params != null && i < params.length; i++) { output.print(" \"<" + params[i].getName() + ">"); if (params[i].isArray()) { output.print("\" +"); } else if (params[i].equals(int.class)) { output.print(" 0x\"+Integer.toHexString(arg" + i + ").toUpperCase() +"); } else { output.print(" \"+arg" + i + " +"); } if (i < params.length - 1) { output.println(" \", \" +"); } } output.println(" \")\");"); // calls to glGetError() are only allowed outside of glBegin/glEnd pairs output.println(" checkGLGetError( txt );"); } } } // end class DebugPipeline //------------------------------------------------------- protected class TracePipeline extends PipelineEmitter { String className; TracePipeline(String outputDir, String outputPackage, Class baseInterfaceClass, Class downstreamClass) { super(outputDir, outputPackage, baseInterfaceClass, null, downstreamClass); className = "Trace" + getBaseInterfaceName(); } protected String getOutputName() { return className; } protected int getMode() { return 0; } protected boolean emptyMethodAllowed() { return false; } protected boolean emptyDownstreamAllowed() { return false; } @Override protected void preMethodEmissionHook(PrintWriter output) { super.preMethodEmissionHook(output); } protected void constructorHook(PrintWriter output) { output.print(" public " + getOutputName() + "("); output.println(downstreamName + " " + getDownstreamObjectName() + ", PrintStream " + getOutputStreamName() + ")"); output.println(" {"); output.println(" if (" + getDownstreamObjectName() + " == null) {"); output.println(" throw new IllegalArgumentException(\"null " + getDownstreamObjectName() + "\");"); output.println(" }"); output.print(" this." + getDownstreamObjectName()); output.println(" = " + getDownstreamObjectName() + ";"); output.print(" this." + getOutputStreamName()); output.println(" = " + getOutputStreamName() + ";"); output.println(" }"); output.println(); } @Override protected void postMethodEmissionHook(PrintWriter output) { super.postMethodEmissionHook(output); output.println("private PrintStream " + getOutputStreamName() + ";"); output.println("private int indent = 0;"); output.println("protected String dumpArray(Object obj)"); output.println("{"); output.println(" if (obj == null) return \"[null]\";"); output.println(" StringBuilder sb = new StringBuilder(\"[\");"); output.println(" int len = java.lang.reflect.Array.getLength(obj);"); output.println(" int count = Math.min(len,16);"); output.println(" for ( int i =0; i < count; i++ ) {"); output.println(" sb.append(java.lang.reflect.Array.get(obj,i));"); output.println(" if (i < count-1)"); output.println(" sb.append(',');"); output.println(" }"); output.println(" if ( len > 16 )"); output.println(" sb.append(\"...\").append(len);"); output.println(" sb.append(']');"); output.println(" return sb.toString();"); output.println("}"); output.println("protected void print(String str)"); output.println("{"); output.println(" " + getOutputStreamName() + ".print(str);"); output.println("}"); output.println("protected void println(String str)"); output.println("{"); output.println(" " + getOutputStreamName() + ".println(str);"); output.println("}"); output.println("protected void printIndent()"); output.println("{"); output.println(" for( int i =0; i < indent; i++) {" + getOutputStreamName() + ".print(' ');}"); output.println("}"); } protected void emitClassDocComment(PrintWriter output) { output.println("/**

Composable pipeline which wraps an underlying {@link GL} implementation,"); output.println(" providing tracing information to a user-specified {@link java.io.PrintStream}"); output.println(" before and after each OpenGL method call. Sample code which installs this pipeline:

"); output.println(); output.println("
");
            output.println("     GL gl = drawable.setGL(new TraceGL(drawable.getGL(), System.err));");
            output.println("
"); output.println("*/"); } protected boolean hasPreDownstreamCallHook(Method m) { return true; } protected void preDownstreamCallHook(PrintWriter output, Method m) { if (m.getName().equals("glEnd") || m.getName().equals("glEndList")) { output.println("indent-=2;"); output.println(" printIndent();"); } else { output.println("printIndent();"); } output.print(" print("); printFunctionCallString(output, m); output.println(");"); } protected boolean hasPostDownstreamCallHook(Method m) { return true; } protected void postDownstreamCallHook(PrintWriter output, Method m) { Class ret = m.getReturnType(); if (ret != Void.TYPE) { output.println(" println(\" = \"+_res);"); } else { output.println(" println(\"\");"); } } private String getOutputStreamName() { return "stream"; } } // end class TracePipeline public static final void printFunctionCallString(PrintWriter output, Method m) { Class[] params = m.getParameterTypes(); output.print(" \"" + m.getName() + "(\""); for (int i = 0; i < params.length; i++) { output.print("+\"<" + params[i].getName() + ">"); if (params[i].isArray()) { output.print("\""); } else if (params[i].equals(int.class)) { output.print(" 0x\"+Integer.toHexString(arg" + i + ").toUpperCase()"); } else { output.print(" \"+arg" + i); } if (i < params.length - 1) { output.print("+\", \""); } } output.print("+\")\""); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy