Search Unity

Calling C++ Plugin

Discussion in 'Editor & General Support' started by gr33nl1nk, Dec 19, 2008.

  1. gr33nl1nk

    gr33nl1nk

    Joined:
    Dec 19, 2008
    Posts:
    92
    Hi, I have a problem using C++ plugin in Unity, I have a C++ Makefile project which I want to use in Unity, and it gave me a lot of problems when i tried to convert it to Mac OS bundle (using XCode), so, my question is, can unity import lib*.so (shared library) from mono script instead of *.bundle?
     
  2. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    .so is not a file ending usually used on Mac OS X, but the file ending doesn't really matter to the OS itself.

    Mac OS X has two types of dynamically loadable modules: .dylib for dynamically linked shared libraries and .bundle for plugin code loaded at runtime.

    Since Mac OS 10.2 I think, the bundle loader can actually load .dylib files in addition to .bundle files, so you could try simply renaming the module so it ends with an .bundle instead of .so

    (You could also try changing your Makefile so it produces a bundle file instead of dylib. This should be done by linking it using gcc -bundle instead of gcc -dynamiclib)
     
  3. gr33nl1nk

    gr33nl1nk

    Joined:
    Dec 19, 2008
    Posts:
    92
    thanks, i got it working now, but what i did slightly different from your suggestion, apparently unity only look for .bundle or .dll in the project /Plugins folder, but you can still use the .so shared library by providing relative path to that library e.g:

    Code (csharp):
    1. [DllImport("Assets/Plugins/libzzz.so")]
    it works just fine, but now I'm getting into another problem, how do I pass objects to a function and takes the return value as an object that is defined in the shared library?

    for example, the dll function takes a Mesh object (which is defined in the dll itself) and output another kind of object, how do i do that?
     
  4. gr33nl1nk

    gr33nl1nk

    Joined:
    Dec 19, 2008
    Posts:
    92
    I got it working a little bit, now i can pass a struct to my dll (or so), like this:

    struct:
    Code (csharp):
    1.  
    2. struct Vector3f {
    3.     double x, y, z;
    4. }
    5.  
    dll prototype:
    Code (csharp):
    1.  
    2. extern "C" {
    3.    Vector3f Foo(Vector3f v); // modify v here
    4. }
    5.  
    mono script:
    Code (csharp):
    1.  
    2. [DllImport("libzzz")]
    3. private static extern Vector3f Foo(Vector3f v);
    4.  
    5. function Start() {
    6.    Vector3f v;
    7.    v.x = 1;
    8.    v.y = 2;
    9.    v.z = 3;
    10.  
    11.    Vector3f ret;
    12.    ret = Foo(v);
    13.  
    14.    Debug.Log(ret.x+", "+ret.y+", "+ret.z);
    15. }
    16.  
    this works fine, but now i want to pass an array of this Vector3f, so I create another structure like this:
    Code (csharp):
    1.  
    2. struct MeshObject {
    3.    [MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
    4.    Vector3f[] vertices;
    5. }
    6.  
    I got this syntax from here: http://mono-project.com/Interop_with_Native_Libraries#Marshaling
    however, when I run the project, unity says:
    Code (csharp):
    1.  
    2. The type or namespace name 'Marshal As' could not be found. Are you missing a using directive or an assembly reference?
    3.  
    So, Im wondering does Unity support this kind of marshalling array of types?
     
  5. gr33nl1nk

    gr33nl1nk

    Joined:
    Dec 19, 2008
    Posts:
    92
    pardon me, it was a stupid mistake, I forgot to type: using System.Runtime.InteropServices,

    but.. Im still having a problem passing an array of struct or double, I have no problem passing an array of int, but the values become garbage when I try to pass an array of double, originally I wanted to pass an array of struct which has three double values x, y, z, but I didnt even manage to pass an array of double to the dll, please kindly advice. thanks.
     
  6. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    You don't pass in an array or structure, you pass in a pointer. You have to send the data around by reference, not by value.

    Code (csharp):
    1.  
    2. [DllImport("libzzz")]
    3. private static extern Vector3f Foo(ref Vector3f[] v);
    Now simply pass in the vector information by reference.
     
  7. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Or use the Marshal Class + System.IntPtr, thats what I did, as I need full control over the passing etc. I can't rely on "automagic"
     
  8. gr33nl1nk

    gr33nl1nk

    Joined:
    Dec 19, 2008
    Posts:
    92
    but isn't an array already a reference(pointer)?, i tried using:

    Code (csharp):
    1. [DllImport("libzzz")]
    2. private static extern Vector3f Foo(ref Vector3f[] v);
    but it gives me something like:

    Code (csharp):
    1. Cannot convert type 'Vector3f[]' to 'Vector3f[]'
    and then i tried to pass the reference of the array as follows:

    Code (csharp):
    1. Vector3f[] points = {new Vector3f(1, 2, 3), new Vector3f(4, 5, 6}}
    2.  
    3. Foo(&points);
    4.  
    then it says:
    Code (csharp):
    1.  
    2. Pointers and fixed sized buffers may only be used in an unsafe context
    but anyway, i think i can already pass an array of struct without using ref keyword before the param as in:

    Code (csharp):
    1. void Foo(Vector3f[] input, int inputSize, Vector3f[] output, int outputSize);
    2.  
    the problem was only i couldnt put the array inside of an object, so i must pass it directly in the function parameter (or i just havent figured out how to do that properly),
    however, im still not sure if that is the best practice to pass things around..

    thanks for the helps guys anyways..
     
  9. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    you can not use in C# unless its unsafe code (as written in the error), which is not possible in Unity

    You pass references through someFunction(ref someObject)


    Also having an array in an object is no problem.
    But you will need three things:

    1. MarshalAs for the specific array
    2. The marshalAa block for the specific class and its size
    3. Don't forget that you must use the Layout.Sequential LayoutKind or you can NOT pass classes to C / C++ at all. (don't assume you are using Layout.Explicit in this case)
     
  10. gr33nl1nk

    gr33nl1nk

    Joined:
    Dec 19, 2008
    Posts:
    92
    thx dreamora, can you give me some examples from the projects you did, as in code snippets on how you did it?
    i just want the protocol to be as simple as possible, probably i will flatten the data if necessary..
     
  11. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Example code:

    Code (csharp):
    1.  
    2.  
    3. [StructLayout(LayoutKind.Sequential)]
    4. public struct V3
    5. {
    6.    public Single x, y, z;
    7.    public V3(Single x, Single y, Single z)
    8.    {
    9.        this.x = x;
    10.        this.y = y;
    11.        this.z = z;
    12.    }
    13.    public static V3 operator +(V3 c1, V3 c2)
    14.    {
    15.       V3 a;
    16.       a.x = c1.x + c2.x;
    17.       a.y = c1.y + c2.y;
    18.       a.z = c1.z + c2.z;
    19.       return a;
    20.    }
    21. }
    22.  
    23. [DllImport(DLLFILE, EntryPoint="iMethod")]
    24. public static extern float iMethod(ref V3 p0, ref V3 p1);
    25.  
    26.  
    FYI just because you use DllImport doesn't mean that it can magically understand the method by your definition, I find this fails more often than not, so make sure you use an EntryPoint definition.