1.0 Introduction

2.0 Compilation and Runtime Information

3.0 Interface Notes

4.0 Component Object Relationships

5.0 Steps to Building an Application with Winforms and HOOPS

 


1.0 Introduction

The HOOPS/Winforms integration consists of C# wrappers to HOOPS/3dGS, HOOPS/MVO, HOOPS/Stream and HOOPS/Parasolid as well as a connection between HOOPS/3dGS and the Winforms 'Panel' and 'Form' GUI objects. This document describes how to use the HOOPS/Winforms integration to build a .Net Winforms application that incorporates the HOOPS/3dAF components. Some familiarity with .Net Winforms, HOOPS/3dGS and HOOPS/MVO is assumed.

Developers should start by compiling and running the basic csharp_simple or vb_simple applications as the starting point for their application. This is the primary example for .Net developers wishing to incorporate the HOOPS/3dAF components into either existing or new .Net applications. The readable source code is located in your <hoops>/demo/csharp/csharp_simple and <hoops>/demo/visual_basic/vb_simple directories. Note: the programming example below utilize the csharp_simple demo as roadmap, but it should be fairly straightforward for VB.Net developers to follow the closely matching vb_simple example.

The <hoops>/demo/csharp/csharp_simple_3dgs_only and <hoops>/demo/visual_basic/vb_simple_3dgs_only directories contains some very simple applications that only use HOOPS/3dgs, and draws into a user-created window.

1.1 Platform/Compiler Support

The HOOPS/Winforms integration is supported under Microsoft Visual Studio 2005 (VC8).


2.0 Compilation and Runtime Information

The following steps are required to compile and run a HOOPS/Winforms based application:

The above files are located in your <hoops>/bin/nt_i386_vc80 directory.

Note: Both C#.Net and VB.Net application code can access these C# wrappers, because Visual Studio 2005 provides built in support for VB apps to access C# interfaces. You simply include the C# references.


3.0 Interface Notes

3.1 General Usage

The routines and classes of the HOOPS/3dGS, HOOPS/MVO and HOOPS/Stream toolkits are all generally accessible via the C# wrappers, with a few exceptions and notes covered below. Developers should refer to the Reference Manual for each component, and can additionally leverage the Intellisense capability of Visual Studio 2005 to dynamically access listings of class members and function/method argument while programming.

Defines

You should also add this "define" to your document somewhere:

#if _M_X64
  using HLONG = System.Int64;
#else
  using HLONG = System.Int32;
#endif

Then, for 64 bit projects, you should define the _M_X64 (you can name this anything you want). You should use "HLONG" in all places where you would normally use a C "long". This is because C#'s "long" is always 64 bit, whereas C's "long" is often 32 bit, and are incompatible. Using HLONG will help ensure compatability. (You can also simply use ints for 32 bit projects and longs for 64 bit projects, but things may get confusing).

 

3.2 HOOPS/3dGS-specific

Routine Prefixes

Each 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 C#, all calls to the HOOPS/3dGS API are made through the HCS class, such as:

HCS.Open_Segment("newsegment");
HCS.Insert_Line(0, 0, 0, 1, 1, 1);
HCS.Close_Segment();

 

HOOPS Routines Available in C#

Most functions available under C are available in C# except for:

Define_Callback_Name
Define_Exit_Handler
UnDefine_Exit_Handler
Define_Callback_Name
UnDefine_Callback_Name
Show_Callback_Name
Set_Driver
QSet_Driver

Two functions are different under C# than C:

UnDefine_Error_Handler
Define_Error_Handler

Both take an HCSU.errfunc object (which is a delegate) as their argument. If null is passed to UnDefine_Error_Handler, it will remove the default HOOPS error handler. If an already registered HCSU.errfunc is passed, that handler will be removed.

Here is an example of declaring an error handler:

public void error_handler(int category, int specific, int severity, int msgc, sbyte ** msgv, int stackc, sbyte ** stackv)
{
}

public void init()
{  
    HCSU.errfunc error_hndlr_ptr = new HCSU.errfunc(error_handler);
    HCS.Define_Error_Handler(error_hndlr_ptr);
    
    HCS.Open_Segment("?picture");
      //  do something
    HCS.Close_Segment();
}

Note: You may have to set your project to "allow unsafe code" in order to use the error handler, as it uses pointers.

 

Pointers and write-back values

The largest difference between using HOOPS with C# 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. In HOOPS C#, arrays can typically be written to without any extra help, while single variables need a "ref" keyword before the object name (similar to the "&" in C/C++).

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 C# by StringBuilder:

StringBuilder ex = new StringBuilder(1024);

ex.EnsureCapacity(1024);

HCS.Show_Alias("?picture", ex);

Console.WriteLine("?picture="+ex);

NOTE: The "StringBuilder" type is used for write-back values. Note that before you begin writing into StringBuilder, you should call EnsureCapacity to guarantee your instance has the minimum specified value. You should use the "string" type for constant string values. These are enforced by the function signatures, so you should not be able to pass in the wrong type.

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 used in a similar manner in C#, with the "ref" keyword:

float x = new float();
float y = new float();
float z = new float();
    
HCS.QShow_Camera_Position("?picture", ref x, ref y, ref z); 
Console.WriteLine(" x="+ x + " y="+ y + " z="+ z); 

Arrays can be used in C# 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 accomplished in C# by:

float[] v1 = {1.0f,0.0f,0.0f};
float[] v2 = {0.0f,1.0f,0.0f};
float[] v3 = new float[3];
HCS.Compute_Cross_Product(v1,v2,v3);
Console.WriteLine(v3[0] + " " + v3[1] + " " + v3[2]); 

HOOPS Keys

Another difference between using HOOPS with C# and C is found when dealing with HOOPS keys. In C#, you should use HLONG (assuming you defined it as mentioned in the Section 3.1 above). Thus, the C code:

HC_KEY key = 0;

key = HC_Open_Segment("?picture");
   ...
HC_Open_Segment_By_Key(key); 

is replaced in C# by:

HLONG key = 0;

key = HCS.KOpen_Segment("?picture");
   ...
HCS.Open_Segment_By_Key(key); 

Datatype Names and Language Declarations in C#

The C# datatypes translate as follows:

HOOPS HOOPS (HC) type C# type
'string' HC type string
'writes string' const char * StringBuilder
'HC_KEY' HC_KEY HLONG (System.Int32 / System.Int64)
'int' int int
'writes int' +" ref int
'float' float float
'writes float' &float ref float
'point' float[3] float[3]
'writes point' &float float[]
'writes bytes' unsigned char * sbyte[]
'writes ints' +" int[]

3.3 HOOPS/MVO-specific

HOOPS/MVO Classes in C#

A majority of HOOPS/MVO classes are available in C#. However, a number of HOOPS/MVO classes are not provided due to some inherent challenges with the wrapper process.

HOOPS/MVO provides the ability create and modify animations. The HOOPS/MVO animation classes that are accessible in C# are HBhvAnimation and HBhvBehaviorManager. These classes give you the ability to build and manipulate a wide variety of keyframe based behaviors as described in sections 10.1 Introduction to Behaviors and Animations to 10.3 Defining Behaviors for basic animations in the HOOPS/MVO Programming Guide. The classes associated with animation that not accessible in C# are listed below.

The following operators are also not accessible in C#:

A number of input and output handlers are not available in C#. They are listed below.

Although HObject and HObjectManager are both availabe in C#, the HOOPS/MVO child classes associated with HObject are not. These include the following:

Most utility classes are available in C# except for the following:

The following HOOPS/MVO classes are also not accessible via C#:

 

Multiple Inheritance

The concept of multiple inheritance is not supported in C#. Thus, access to certain HOOPS/MVO classes that utilize multiple inheritance is limited. Specifically, these classes were wrapped with only one class inherited. The following is a list of the C++ MVO classes that use multiple inheritance and what single class they now inherit from in C#.

HOOPS/MVO Class Parent Class in C# Parent Classes in C++
HBaseView HUpdateListener HUpdateListener, HMouseListener, HObjectManipulationListener
HTCObjectRotate HBaseOperator HBaseOperator, HTClient

 

Datatypes

Most HOOPS/MVO datatypes are accessible in C# but there are some datatypes that have not gone through the wrapper process. They appear in the C# environment with the SWIGTYPE prefixed to their datatype name. Although methods that use these datatypes can be seen with Intellisense, any code calling these methods will not compile. Below is a list of methods that cannot be called in C# because they used datatypes that have not gone through the wrapper process completely.

HOOPS/MVO Class Inaccessible HOOPS/MVO Method
HAnimationListener public virtual int ObjectCollisionEvent(SWIGTYPE_p_HBhvTargetObject tob)
HAnimationListener public virtual int ObjectNoCollisionEvent(SWIGTYPE_p_HBhvTargetObject tob)
HAnimationListener public virtual int AnimationFinishedEvent(SWIGTYPE_p_HBhvAnimation ainst)
HBaseModel public SWIGTYPE_p_HBhvBehaviorManager GetBhvBehaviorManager()
HBaseModel public void SetBhvBehaviorManager(SWIGTYPE_p_HBhvBehaviorManager BehaviorManager)
HBaseView public bool SetStencilProbe(SWIGTYPE_p_HStencilProbe sp)
HBaseView public SWIGTYPE_p_HUtilityAntialiasing GetAntialiasing()
HBaseView public SWIGTYPE_p_HStencilProbe GetStencilProbe()
HBaseView public SWIGTYPE_p_HSharedKey GetSharedKey()
HDebugZBuffer public void OpenglFinishPicture(SWIGTYPE_p_ht_net_rendition nr, bool swap_buffers)
HImErrorHandler public static void CallbackEntryPoint(int category, int specific, int severity, int msgc, SWIGTYPE_p_p_char msgv, int stackc, SWIGTYPE_p_p_char stackv)
HImUtility public static void set_clip_rectangle(SWIGTYPE_p_ht_net_rendition nr, SWIGTYPE_p_ht_segment_info si)
HImUtility public static void suppress_3d_geometry(SWIGTYPE_p_ht_net_rendition rendition, SWIGTYPE_p_ht_geometry geo3)
HImUtility public static void draw_gradiated_window_background(SWIGTYPE_p_ht_net_rendition rendition, SWIGTYPE_p_ht_int_rectangle extent)
HImUtility public static void draw_annotation_lines(SWIGTYPE_p_ht_net_rendition nr, SWIGTYPE_p_ht_polyline poly)
HImUtility public static void draw_segment_in_background(SWIGTYPE_p_ht_net_rendition nr, SWIGTYPE_p_ht_dc_point points, SWIGTYPE_p_ht_rgba colors, SWIGTYPE_p_ht_plane planes, float[] hparams, int param_width, int param_flags)
HImUtility public static void draw_dc_polyline_infront(SWIGTYPE_p_ht_net_rendition rendition, int count, SWIGTYPE_p_ht_dc_point geo3)
HImUtility public static void draw_device_independent_line_weights(SWIGTYPE_p_ht_net_rendition rendition, int count, SWIGTYPE_p_ht_dc_point geo3)
HImUtility public static void drawTextInfront(SWIGTYPE_p_ht_net_rendition rendition, SWIGTYPE_p_ht_text_info text_info)
HImUtility public static void visible_hlr_polyline(SWIGTYPE_p_ht_net_rendition rendition, int count, SWIGTYPE_p_ht_dc_point geo3)
HIOConnector public virtual bool GetHoopsEntities(IntPtr pKernelEntity, SWIGTYPE_p_vlist_s ret_HoopsKeysList)
HIOConnector public virtual bool GetKernelEntities(MVO_POINTER_SIZED_INT key, SWIGTYPE_p_vlist_s ret_KernelEntitiesList)
HOpCameraWalk public static int ImageAction(SWIGTYPE_p_HImageRegion ii, IntPtr data, SWIGTYPE_p_HButtonState keyup)
HOpCameraWalk public void OnButtonWalk(string action, SWIGTYPE_p_HButtonState buttonstate)
HSelectionSet public virtual SWIGTYPE_p_vlist_s GetSelectionList()
HSensorListener public virtual int SensorActivatedEvent(SWIGTYPE_p_HBhvSensor sensor)
HUtility public static void ShowContentsWithPath(string entitytypes, SWIGTYPE_p_p_vlist_s ret_pathlist, bool storePath, bool includeIncludes, bool filterIncludes)
HUtility public static void ShowContentsWithPath(string entitytypes, SWIGTYPE_p_p_vlist_s ret_pathlist, bool storePath, bool includeIncludes)
HUtility public static void ShowContentsWithPath(string entitytypes, SWIGTYPE_p_p_vlist_s ret_pathlist, bool storePath)
HUtility public static void ShowContentsWithPath(string entitytypes, SWIGTYPE_p_p_vlist_s ret_pathlist)
HUtility public static void MakeViewSnapshot(HBaseView view, int width, int height, SWIGTYPE_p_p_char data)

Note that pointers to vlist and vhash are also not accessible via C#.

 

Macros and Function Pointers

MVO macros are not available in C#. Function pointers are also not supported. Although methods with function pointers in their signatures can be seen by Intellisense, any calls to them will not compile. Member variables which are function pointers cannot be accessed either. Generally, if a parameter or variable has a data-type prefixed with SWIGTYPE, it is unlikely that it can be used in C#. In the following example, the HIOManager's RegisterConnector method cannot be used in C# because the parameters Create and Free are function pointers. In the C# function declaration, it can be seen that Create and Free have datatypes prefixed with SWIGTYPE.

 
    public virtual HIOConnector HIOManager::RegisterConnector(string file_type, SWIGTYPE_p_f_p_void__p_void Create, SWIGTYPE_p_f_p_void__void Free)

The following is a list of methods that cannot be accessed in C# because they have functions pointers in their signature:

HOOPS/MVO Class HOOPS/MVO Method
HBaseView public SWIGTYPE_p_f_p_q_const__char_unsigned_int_p_void__void GetEmitMessageFunction()
HBaseView public SWIGTYPE_p_f_p_ht_net_rendition__void GetEventCheckerCallback()
HBaseView public SWIGTYPE_p_f_unsigned_int_r_int__bool GetKeyStateCallback()
HBaseView public void SetEmitMessageFunction(SWIGTYPE_p_f_p_q_const__char_unsigned_int_p_void__void new_emit_message_function)
HBaseView public void SetEmitMessageFunction(SWIGTYPE_p_f_p_q_const__char_unsigned_int_p_void__void new_emit_message_function, IntPtr user_data)
HBaseView public void SetEventCheckerCallback(SWIGTYPE_p_f_p_ht_net_rendition__void EventChecker)
HBaseView public void SetKeyStateCallback(SWIGTYPE_p_f_unsigned_int_r_int__bool KeyState)
HBaseView public uint SetSignalNotify(int signal, SWIGTYPE_p_f_int_p_void_p_void__bool callback, IntPtr user_data)
HIOManager public HIOConnector RegisterConnector(string file_type, SWIGTYPE_p_f_p_void__p_void Create, SWIGTYPE_p_f_p_void__void Free)
HTClient HTClient(float interval, HTCStyle style, SWIGTYPE_p_f_float_float_p_void__bool tick_function, IntPtr user_data)
HTClient HTClient(float interval, HTCStyle style, SWIGTYPE_p_f_float_float_p_void__bool tick_function)
HTClient public SWIGTYPE_p_f_float_float_p_void__bool GetTickFunction()
HTClient public void SetTickFunction(SWIGTYPE_p_f_float_float_p_void__bool tick_function)

 

Variant Methods

Although some HOOPS/MVO classes are availabe in C#, not all their methods can be used because of the design of the C# language. In these cases, HOOPS provides a variant especially designed for C# users. Below is a list of classes, their inaccessible methods and their C# variants.

Class Inaccessible Method C# Variant Method
HSelectionItem virtual const HC_KEY * HSelectionItem::GetFullPathKeys (HBaseView *view) virtual void HSelectionItem::GetFullPathKeys (HBaseView *view, System.Int32/System.Int64[] path)
HSmartSelItem virtual const HC_KEY *const HSmartSelItem::GetIncludeKeys () const virtual void HSmartSelItem::GetIncludeKeys (System.Int32/System.Int64[] includes) const
HSmartSelItem virtual const HC_KEY * HSmartSelItem::GetFullPathKeys (HBaseView *view) virtual void HSmartSelItem::GetFullPathKeys (HBaseView *view, System.Int32/System.Int64[] path)
HShellObject int const * HShellObject::GetFlist () const void HShellObject::GetFlist (int[] flist) const
HShellVertexData float const *const HShellVertexData::GetFIndexData () const void HShellVertexData::GetFIndexData (float[] data) const

Accessing Protected Members

Protected members are not wrapped and must be accessed via their public accessor functions. However, not all classes have public accessors for every protected members. Please inform Techsoft support if you encounter a class which does not have the needed public accessors and we will get you a patch.


4.0 Component Object Relationships

This section discusses the relationship between .Net Winforms and HOOPS/3dAF components. Building an application with both these toolkits minimally involves using the following objects from each component.

Winforms

A .Net Winforms application typically has a master Form object, which contains child forms. Each child form may contain a Panel.

 

HOOPS/Winforms

At least one HNPanel and HNForm object, where the Panel gets attached to the Form. You usually create a custom panel and form derived from HNPanel and HNForm.

 

HOOPS/MVO

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:

HOOPS_winforms_arch.gif


5.0 Steps to Building an Application with .Net Winforms and HOOPS

Programming with an object oriented GUI framwork like .Net Winforms 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 .Net Winforms and HOOPS/3dAF specifically requires creation and initialization of:

5.1 Creating and Initializing the Application

A .Net Winforms application usually creates a master Form object which implements the function Main(). The csharp_simple application does this in it's primary csharp_simple.cs source file as follows:

public class SimpleAppForm : Form
{
   ...
  
    static void Main()
    {
        SimpleAppForm hoops = new SimpleAppForm();
        Application.Run(hoops);
    }
    
    ...
}

 

5.2 Creating and Initializing HOOPS/Winforms Objects

The HOOPS/Winforms integration consists of a customized .Net Winforms 'Form' and 'Panel' called HNForm and HNPanel, as diagramed up above. (Again, the Panel will get attached to the form.) As many pairs of these objects can be created as needed to implement the GUI's design. Your application should define custom HNForm and HNPanel classes, as shown in csharp_simple source.

Custom HNPanel definition taken from the csharp_simple project's SimpleHNPanel.cs source file:

public class SimpleHNPanel : HNPanel
{
    // Constructor which calls the Init() method of the class  
    public SimpleHNPanel(): base()
    {
        Init();
    }


    // This method will set up the default HOOPS/MVO view for the panel and attach a HOOPS/MVO default operator 
    public new void Init()
    {
        // contents reviewed later
    }
    
    ...
}

Here is custom HNForm definition taken from the csharp_simple project's SimpleHNForm.cs source file. Note that it creates the custom HNPanel object and initializes the form:

public class SimpleHNForm : HNForm
{
    ...


    // Sets up the panel and window 
    public void Init(object sender, EventArgs e)
    {
        // set up the panel that HOOPS will draw into
        m_pHNPanel = new SimpleHNPanel();

        Instance = (this.IsMdiChild) ? ((HForm)this.MdiParent).win_count : 0;
            
        // first set up the window, then set the axis triad options
        Init_Form();
        
        m_pHNPanel.m_pHView.Update();
        m_pHNPanel.m_pHView.SetAxisMode(AxisMode.AxisOn);
        m_pHNPanel.m_pHView.AdjustAxisWindow();
        
        ...
    }
    
    ...
}

Finally, we can note that the fileNew and fileOpen methods of main app object (SimpleAppForm, again located in csharp_simple.cs) will create the custom HNForm object:

public class SimpleAppForm : Form
{
        ...
        
        private void fileNewMenu_Click(object sender, EventArgs e)
        {
            SimpleHNForm frmchild = new SimpleHNForm();
            frmchild.MdiParent = this;
            frmchild.Show();
            win_count++;
        }


        private void fileOpenMenu_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Open";
            dlg.Filter = "HMF/HSF files (*.hmf, *.hsf)|*.hmf;*.hsf" +
                         "|All files (*.*)|*.*";

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                SimpleHNForm frmchild = new SimpleHNForm();
                frmchild.MdiParent = this;
                frmchild.Show();

                frmchild.LoadFile(dlg);
                win_count++;
            }
            dlg.Dispose();
        }
        
        ...
}

5.3 Creating and Initializing HOOPS/MVO Objects

HDB

One global pointer to a HOOPS/MVO HDB object should be declared and initialized in your application's main class. The csharp_simple app does this in the main SimpleAppForm constructor (located in csharp_simple.cs) :

public class SimpleAppForm : Form
{
    ...
    
    // Constructor which initializes hoops database and GUI features of the main window */
    public SimpleAppForm()
    {
        win_count = 1;

        m_pHDB = new HDB();
        m_pHDB.Init();    

        ...
    }
    
    ...
}

 

HBaseModel

Multiple HBaseModel objects can be created as needed. The csharp_simple app creates one for every SimpleHNPanel object (i.e., there is a one-to-one mapping of HBaseModel to SimpleHNPanel objects) and does so in the SimpleHNPanel::Init :

    
    public class SimpleHNPanel : HNPanel
    {
      ...

      public new void Init()
      {
        ...

        m_pHModel = new HSimpleModel();
        m_pHModel.Init();

        ...
      }

    }

 

HBaseView

Multiple HBaseView objects can be created as needed, with one object usually being created for each HNPanel. 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 a HNPanel. This requires that the HNPanel, to which the HBaseView will be attached, already exist prior to creating the HBaseView object.

Your app should create the HBaseView object in your overloaded HNPanel::Init method. Here is the csharp_simple example taken from csharp_simple.cs :

public class SimpleHNPanel : HNPanel
{
    ...

    public new void Init()
    {
        ...

        m_pHView = new HSimpleView(m_pHModel, "?picture" + SimpleHNForm.Instance, "opengl", "", winid);
        m_pHView.Init();
         
        ...
    }

}


HSelectionSet

The HBaseView class and HNPanel class contain pointers to a HSelectionSet object. A selection set class would typically be created and initialized during HNPanel initialization. After creation, it's important to pass the HSelectionSet operator into HBaseView by calling HBaseView::SetSelection. The csharp_simple app does this in the overloaded method of HNPanel::Init method:

public class SimpleHNPanel : HNPanel
{
    ...

    public new void Init()
    {
        ...

        // view and model initialization goes here, and was discussed previously
        
        // Set up the custom HSelectionSet object
        m_pHSelection = new HSimpleSelectionSet(m_pHView);
        m_pHView.SetSelection(m_pHSelection);
        m_pHView.GetSelection().Init();
         
        ...
    }

}


HBaseOperator

The HBaseView class and HNPanel class contains pointers to a HBaseOperator object. A default operator would typically be created and initialized during HNPanel initialization. After creating, you should set it to be the current operator by calling the utility method HNPanel::SetCurrentOperator.. The csharp_simple app does this in the overloaded method of HNPanel::Init method:

public class SimpleHNPanel : HNPanel
{
    ...

    public new void Init()
    {
        ...
        
        // Set the default operator
        m_pHOperator = new HOpCameraManipulate(m_pHView);
        m_pHView.SetCurrentOperator((HBaseOperator)m_pHOperator);
         
        ...
    }

}