You are here: Home Downloads About Coin3D Related projects CoinJava
Navigation
Log in


Forgot your password?
 
Document Actions

CoinJava

CoinJava is a Java wrapper for Coin3D, developed during a student project at the Faculty of Informatics and e-Learning (AITeL) in Trondheim, in co-operation with Systems in Motion. CoinJava is in beta status and is currently not under active development.

Download CoinJava

CoinJava comes in two parts - a native shared library and a Java package contained in a JAR file. You also probably want the SoSwing module for building GUI applications.

The native shared library

This library is of course platform dependent, and must be compiled together with Coin for each platform it is to be used on. A Linux binary is available for download; its library dependencies will be roughly the same as for the Coin library itself.

The Java package

The bytecode in the JAR file is platform independent, and it should not be necessary to recompile it for each platform.

SoSwing

The bytecode in the JAR file is platform independent, and it should not be necessary to recompile it for each platform.

Installation

  1. Download a CoinJava native shared library for your platform if one is avilable, or download the source and compile yourself.
  2. Make sure the libCoinJava.so file is avilable somewhere on the library path (include its directory in LD_LIBRARY_PATH).
  3. Download CoinJava.jar, and either put it in your CLASSPATH or in $JAVA_HOME/jre/lib/ext.
  4. Download SoSwing.jar, and either put it in your CLASSPATH or in $JAVA_HOME/jre/lib/ext.
  5. In order to actually run any CoinJava applications, you will need to have GL4Java installed.

How to use Coin from Java

a guide for those used to using Coin from C++

The JNI binding

The JNI binding for Coin consists of two libraries. One is a Java equivalent of Coin, residing in CoinJava.jar. The other is a native C++ library, residing in libCoinJava.so. The latter is responsible for converting Coin calls from the Java Virtual Machine to calls to the native Coin library (libCoin.so).

When creating Java programs using CoinJava, CoinJava.jar must be present in the CLASSPATH. Also, the JVM must know where to find the native CoinJava library libCoinJava.so. The Java program should load the native library as it is initialized.

For the JVM (under Linux!) to find libCoinJava.so, you must set the environment variable LD_LIBRARY_PATH=<directory-of-libCoinJava.so>. The method for other OS'es may differ.

Before any usage of Coin classes, the native library must be loaded by Java. If you use SoSwing, this is automatically done in the call to SoSwing.init(). If you for some reason want to use Coin classes before this call, or you don't use SoSwing, you should have the following code in your Java program:

static {
  System.loadLibrary("CoinJava");
}

The best placement of this is as the first code in the class scope of the same class as your main() method. What is important is that the call to System.loadLibrary() takes place before any usage of the Coin library.

Writing code

There are a few distinct differences from using Coin in C++ to using Coin in Java.

  • There are no pointers in Java; if you hadn't noticed, please take a Java course before continuing. This means that a period (.) is used wherever you would use the -> operator in C++.

  • Java has the nice boolean data type, not being equal to the integer data type. Coin uses integers (oftened typedef'ed through SbBool) to represent boolean values. Therefore, these are automatically wrapped as integers in the Java library. Wherever you, as a Java programmer, would like to tell the Coin library false or true, you must instead tell it 0 or any other value (typically 1).

    A few helpful tips:

    A function taking a integer argument representing a boolean could be called like this:

        boolean b = true;
        foo(b ? 1:0);
      

    If a function returns an integer representing a boolean, its return value should be checked for truth like this:

        if (foo() != 0) { ... }
      

    or

        boolean b = foo() != 0;
        if (b) { ... }
      
  • Whenever a Coin function takes pointers or references to primitive data types as arguments, you must use arrays in Java. A pointer to a primitive data type may actually be a pointer to the first element of an array of the primitive data type. Also, the value pointed or referred to may be altered by the function, but Java does not support references to primitive types. Unfortunately, this feels a bit awkward, but it is nonetheless necessary.

    Retrieving the values from an SbVec3f object can be done like this:

        SbVec3f vec3f = new SbVec3f(1.0f, 2.0f, 3.0f);
        float[] f1 = new float[1],
                f2 = new float[1],
                f3 = new float[1];
        vec3f.getValue(f1, f2, f3);
        float sum = f1[0] + f2[0] + f3[0];
      
  • Field values in Coin objects can typically be accessed as "object.field" in C++. Public fields cannot be wrapped directly to Java, so instead accessor methods are generated. The proper way of getting "object.field" in Java will therefore be "object.field()".

    Accessor methods have the same name as the field they access. Please be aware that since Java has no operator overloading, one has to set field values by using "object.field().setValue(...)", not "object.field = ...".

    If the public field is of a primitive data type, you can only access the value, not set it.

  • Overloaded C++ operators are available as methods. For example, the operator+= in SbVec3f is avilable as opAddEq() in Java. The assignment operator is always available; if one is not defined in the class the C++ default assignment operator is used instead. See the CoinJava JavaDoc for details.

  • Coin callbacks are handled by using Java interfaces. To implement a callback function in Java, implement the callback's interface. Callback registrar functions have been altered in the Java version to take as an argument a reference to an object implementing the callback in question, while typical user data arguments have been removed.

    Callback interfaces are named after their equivalent C++ typedefs, or their equivalent C++ argument names (taken from the registrar function), with the string "Callback" appended. See the JavaDoc documentation of the CoinJava library.

  • Every Coin object in Java has a corresponding native C++ object. Since C++ does not feature automatic garbage collection as Java do, these objects must be deleted explicitly. You can do this yourself by invoking the delete() method on the Java object, or you can instruct Java's garbage collector to automatically do it for you when the Java object is garbage collected.

    Many of the Java objects already has this feature turned on by default, such as the objects returned from some of the overloaded operators. To manually turn it on, call the delOnGc() method on the Java object. This method returns a reference to self, so you can for example do it like this:

        SbVec3f vec3f = new SbVec3f().delOnGc();
      

    The native SbVec3f object will now automatically be garbage collected together with the Java object. Note that since you are not allowed to have methods whose only difference is the return value in Java, you might need to add an explicit cast in some cases.

  • When a Coin function returns an object, there is no easy way to tell if the object is of the declared return type or a descendant of it. The Java object returned will thus always be of the declared return type, but this can create a problem if you want to cast it.

    For example, if you use an SoSearchAction to locate a node, and then invoke the getPath().getTail() method, it will return an SoNode. However, the object will probably be of a descendant of SoNode, perhaps an SoMaterial node. Now, using the normal Java cast operator will result in a ClassCastException, rather it must be done like this:

        SoMaterial material =
            new SoMaterial(node.getCxxwrapImpl());
      

    What happens here is that a new Java object is created, telling Java the correct type. Of course, you could also do it like this:

        SoNode node = new SoMaterial(
            searchaction.getPath().getTail().getCxxwrapImpl());
            SoMaterial material = (SoMaterial) node;
      

    In the above case you would of course need to add a check to see that the SoSearchAction actually found something (using isFound()), as if not 'null' would be returned and your program stop with a NullPointerException.

Wrapping Coin

Using the publicly available cxxwrap utility, you can generate a Java wrapping of the Coin library yourself.

Please download CoinJava-wrapper-1.1.tar.bz2 before you begin; this file contains step-by-step instructions on how to proceed.

Note: The wrapper source code available here includes some proprietary functionality not available in the latest version of cxxwrap. If you want to actually use the generated wrapper code, please instead download the ready-made code.

If this is not acceptable (e.g. you are trying to build a wrapper for Coin-2) there is a new version of the above file available which contains instructions for including the proprietary functionality in the generated wrapper code. Hopefully the necessary features to do this can be integreated into the official cxxwrap version, but in the mean time download CoinJava-wrapper-1.2.tar.bz2.

Related projects
Resources