The HOOPS/Java integration consists of Java wrappers to HOOPS/3dGS, HOOPS/MVO, and HOOPS/Stream, as well as a connection between HOOPS/3dGS and the Java/Swing 'HCanvas'' GUI objects. This document describes how to use the HOOPS/Java integration to build a Java/Swing application that incorporates the HOOPS/3dAF components. Some familiarity with Java/Swing, HOOPS/3dGS and HOOPS/MVO is assumed.
Developers should start by compiling and running the basic java_simple application as the starting point for their application. This is the primary example for Java developers wishing to incorporate the HOOPS/3dAF components into either existing or new Java applications. The readable source code is located in your <hoops>/demo/java/java_simple directory.
The <hoops>/demo/java/java_simple_3dgs_only directory contains some very simple applications that only use 3dgs, and draws into a user-created window.
The <hoops>/demo/java/java_standard directory contains some legacy standalone java examples that draw into a HOOPS/3dGS standalone window. These example are solely intended to show how to acess the HOOPS/3dGS API from Java.
The HOOPS/Java integration is supported under the J2SE Development Kit 5.0 (JDK 5.0) Update 7, on theWindows 32-bit platform.
The following steps are required to compile and run a HOOPS/Java based application:
With the exception of jawt.dll (which comes from the JDK installation's jre/bin
directory), the above files should all be located in your <hoops>/bin/nt_i386_vc80 directory on Windows, and your <hoops>/bin directory under Solaris and Linux.
The routines and classes of the HOOPS/3dGS, HOOPS/MVO and HOOPS/Stream toolkits are all generally accessible via the Java wrappers, with a few exceptions and notes covered below. Developers should refer to the Reference Manual for each component, and can additionaly leverage the Intellisense capabilities of the NetBeans IDE to see listings of class members and function/method arguments.
Each HOOPS/3dGS routine name, such as Insert_Polyline in your HOOPS program must have a prefix before the name will actually be usable on your computer system. The prefix varies depending on which language you're calling from, and sometimes depending on the brand of the language you're calling from. When calling from Java, all calls to the HOOPS/3dGS API are made through the HJ class, such as:
StringBuffer ex = new StringBuffer (""); HJ.Show_Alias("?picture", ex);
Most functions available under C are available in Java except for:
Define_Callback_Name
Define_Exit_Handler
UnDefine_Exit_Handler
Define_Callback_Name
UnDefine_Callback_Name
Show_Callback_Name
Set_Driver
QSet_Driver
Define_Error_Handler.
The largest difference between using HOOPS with Java and C is found when you have a write-back value, i.e. you pass a pointer to a function and it writes a value or values to that location. Because Java does not have pointers, we have to use other means of passing in by reference.
For example, the C HOOPS code that uses a char*:
char ex[1024]; HC_Show_Alias("?picture", ex); printf("?picture=%s\n",ex);
is replaced in Java by StringBuffer:
StringBuffer ex = new StringBuffer (""); ex.ensureCapacity(1024); HJ.Show_Alias("?picture", ex); System.out.println("?picture="+ex);
NOTE: You must always pass a new or empty StringBuffer, as HJ uses append internally to return the string. Note that you must also call ensureCapacity to guarantee the buffer has a minimum size before anything can be written into it.
The C HOOPS code that uses &[float_value]:
float x,y,z; HC_QShow_Camera_Position("?picture", &x, &y, &z); printf("x=%f y=%f z=%f\n", x, y, z);
is replaced in Java by single element float arrays:
float[] x = new float[1]; float[] y = new float[1]; float[] z = new float[1]; HJ.QShow_Camera_Position("?picture", x, y, z); < System.out.println("x=" + x[0] + "y=" + y[0] + "z=" + z[0]);
Arrays can be used in Java in a similar manner as they are used in C. Thus, the C HOOPS code:
float v1[3] = {1.0f,0.0f,0.0f}; float v2[3] = {0.0f,1.0f,0.0f}; float v3[3]; HC_Compute_Cross_Product(v1,v2,v3); printf("%f %f %f\n", v3[0], v3[1], v3[2]);
is replaced in Java by:
float[] v1 = {1.0f,0.0f,0.0f}; float[] v2 = {0.0f,1.0f,0.0f}; float[] v3 = new float[3]; HJ.Compute_Cross_Product(v1,v2,v3); System.out.println( v3[0]+" "+v3[1]+" "+ v3[2]);
It's important to allocate enough room in the array, lest HOOPS writes into unallocated memory and causes a segfault.
The Java datatypes translate as follows:
| HOOPS | HOOPS (HC) type | Java type |
| 'string' | HC type | String |
| 'writes string' | const char * | StringBuffer |
| 'HC_KEY' | HC_KEY | int |
| 'int' | int | int |
| 'writes int' | +" | int[1] |
| 'float' | float | float |
| 'writes float' | &float | float[1] |
| 'point' | float[3] | float[3] |
| 'writes point' | &float | float[] |
| 'writes bytes' | unsigned char * | sbyte[] |
| 'writes ints' | +" | int[] |
Do not use BStreamFileToolkit::PrepareBuffer. Instead, do the following:
This section discusses the relationship between Java and HOOPS/3dAF components. Building an application with both these toolkits minimally involves using the following objects from each component.
A Java/Swing application would typically have a master application object and a JFrame object.
At least one HJCanvas (you would typicially create a custom canvas derived from HJCanvas). This will get added to the JFrame object mentioned above.
HBaseModel, HBaseView, an Operator class derived from HBaseOperator. Applications that want to implement selection of Geometry will also need a HSelectionSet object. These objects are all connected by private data members which store pointers to other objects in the following manner:
Programming with an object oriented GUI framwork like Java/Swing involves creating a set of objects and defining the ways in which they are connected, the manner in which they send and receive messages, and then launching the framework's event loop. Building an application using Java/Swing and HOOPS/3dAF specifically requires creation and initialization of:
A Java/Swing application typically creates a master application object which implements the function main(). The java_simple application provides an example which also creates a custom class called JSimpleApplication and calls its CreateNewDocument method:
public class java_simple { static public JSimpleApplicaton theApp; public static void main(String[] argv) { theApp = new JSimpleApplicaton(); theApp.CreateNewDocument(); } }
The sample JSimpleApplication implementation includes a method called CreateNewDocument which will create a custom JFrame object:
class JSimpleApplicaton { ... public void CreateNewDocument() { new JSimpleDocument(); } }
class JSimpleDocument extends JFrame { }
The GUI aspect of the HOOPS/Java integration simply consists of a customized Java/Swing canvas called HJCanvas as diagramed up above. As many HJCanvas objects can be created as needed to implement the GUI's design. The application should create a custom HJCanvas class, as shown in java_simple:
class SimpleHJCanvas extends HJCanvas { }
Your custom canvas will most likely be created and attached in your custom JFrame constructor:
class JSimpleDocument extends JFrame { private SimpleHJCanvas m_SimpleHJCanvas; public JSimpleDocument() { ... m_SimpleHJCanvas = new SimpleHJCanvas(); getContentPane().add(m_SimpleHJCanvas); setVisible(true); } }
One global pointer to a HOOPS/MVO HDB object should be declared and initialized in the application's main class. The java_simple app does this in the JSimpleApplication constructor:
class JSimpleApplicaton { ... public JSimpleApplicaton() { m_HDB = new HDB(); m_HDB.Init(); } ... }
Multiple HBaseModel objects can be created as needed. The java_simple app creates one for every SimpleHJCanvas object (i.e., there is a one-to-one mapping of HBaseModel to SimpleHJCanvas objects) and does so in the SimpleHJCanvas constructor:
class SimpleHJCanvas extends HJCanvas { public SimpleHJCanvas() { super(); m_HModel = new HSimpleModel(); m_HModel.Init(); } }
Multiple HBaseView objects can be created as needed, with one object usually being created for each HJCanvas. The HBaseView needs a valid native GUI window id passed to its constructor on object creation; this information is used to connect a HOOPS/3dGS output driver instance to HJCanvas. This requires that the HJCanvas, to which the HBaseView will be attached, already exist prior to creating the HBaseView object.
The app should create the HBaseView object in an overloaded HJCanvas::Init method. This method is called by the base class HJCanvas in its HJCanvas::paint method the first time it is called, which first ensures that the widget is alive and thus the Window ID is valid and the HBaseView object can be created. The java_simple example:
class SimpleHJCanvas extends HJCanvas { ... public void Init() { if (m_HView == null) { long hnd = get_window_handle(getGraphics()); SWIGTYPE_p_void swig; swig = new SWIGTYPE_p_void(hnd, true); m_HView = new HSimpleView(m_HModel, "", "opengl", "", swig); m_HView.Init(); ... } } ... }
The HBaseView class has a member HBaseView::m_pSelection that is a pointer to an HSelectionSet object. Multiple HSelectionSet object can be created as needed, but usually there is a one to one mapping of HSelectionSet to HBaseView objects. Similar to the initial HBaseOperator, the selection set object would typically be created and initialized in the HJCanvas::Init method. After creating it, it's important to pass it's pointer into HBaseView by calling HBaseView::SetSelection :
class SimpleHJCanvas extends HJCanvas { ... public void Init() { if (m_HView == null) { ... m_HSelectionSet = new HSimpleSelectionSet(m_HView); m_HSelectionSet.Init(); m_HView.SetSelection(m_HSelectionSet); ... } } }
A default operator should be created during view initialization, and made the current operator which is done by calling the HJCanvas::SetCurrentOperator utility function. (This utility will set the HBaseView::m_pOperator member which is a pointer to an HBaseOperator). .The java_simple app does this in the overloaded method of HJCanvas::Init :
class SimpleHJCanvas extends HJCanvas { ... public void Init() { if (m_HView == null) { ... // Set the default operator m_HOperator = new HOpCameraManipulate(m_HView); m_HView.SetCurrentOperator((HBaseOperator)m_HOperator); ... } } }