Horde3D

Next-Generation Graphics Engine
It is currently 24.11.2024, 20:17

All times are UTC + 1 hour




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Horde3D with SWIG?
PostPosted: 11.03.2011, 15:34 
Offline

Joined: 15.09.2010, 18:31
Posts: 53
I've been thinking a while about using SWIG for Horde3D C API -> D (in my case) bindings generation. We could integrate it with CMAKE build and add few other languages more (as options to cmake).

I think it's better solution than current python scripts which have no idea about lexical or semantics. What do You think about it?


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 11.03.2011, 20:31 
Offline
Tool Developer

Joined: 13.11.2007, 11:07
Posts: 1150
Location: Germany
I neither have experience with SWIG nor with D, but if binding generation for D could be automated using SWIG and CMake this would be perfect to maintain the language bindings.


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 11.03.2011, 22:39 
Offline

Joined: 15.09.2010, 18:31
Posts: 53
Neither do I (swig/cmake), but i think i can try to construct proper patch for community repo (not much of work). SWIG wrapping looks like below, and is convenient to use because it *should* bridge types of both languages properly (i.e const char* might be string).

There are the downsides though - as You can see there are bridge functions which might have memory allocations which isn't cool anymore. I'm not sure if it's affordable to have these in graphics engine. Since I still don't feel confident in this area, could anyone hint me if it's worth to pay this performance cost for convenience?

Lastly, i would see this like Bindings -> D -> swig -> CMakeLists.txt . And about other languages, should i add similar directories for other supported languages or it's not interesting enough to support them in horde3d?

Ps. If someone else already played with cmake / swig and would like to make it work, just tell me so i won't double efforts

Code:
(...)
// Support for throwing D exceptions from C/C++.
typedef enum {
  SWIG_DException = 0,
  SWIG_DIllegalArgumentException,
  SWIG_DIllegalElementException,
  SWIG_DIOException,
  SWIG_DNoSuchElementException,
} SWIG_DExceptionCodes;

typedef void (* SWIG_DExceptionCallback_t)(const char *);

typedef struct {
  SWIG_DExceptionCodes code;
  SWIG_DExceptionCallback_t callback;
} SWIG_DException_t;

static SWIG_DException_t SWIG_d_exceptions[] = {
  { SWIG_DException, NULL },
  { SWIG_DIllegalArgumentException, NULL },
  { SWIG_DIllegalElementException, NULL },
  { SWIG_DIOException, NULL },
  { SWIG_DNoSuchElementException, NULL }
};

(..)
#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT void SWIGRegisterExceptionCallbacks_Horde3D(
  SWIG_DExceptionCallback_t exceptionCallback,
  SWIG_DExceptionCallback_t illegalArgumentCallback,
  SWIG_DExceptionCallback_t illegalElementCallback,
  SWIG_DExceptionCallback_t ioCallback,
  SWIG_DExceptionCallback_t noSuchElementCallback) {
  SWIG_d_exceptions[SWIG_DException].callback = exceptionCallback;
  SWIG_d_exceptions[SWIG_DIllegalArgumentException].callback = illegalArgumentCallback;
  SWIG_d_exceptions[SWIG_DIllegalElementException].callback = illegalElementCallback;
  SWIG_d_exceptions[SWIG_DIOException].callback = ioCallback;
  SWIG_d_exceptions[SWIG_DNoSuchElementException].callback = noSuchElementCallback;
}


// Callback for returning strings to D without leaking memory.
typedef char * (* SWIG_DStringHelperCallback)(const char *);
static SWIG_DStringHelperCallback SWIG_d_string_callback = NULL;

#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT void SWIGRegisterStringCallback_Horde3D(SWIG_DStringHelperCallback callback) {
  SWIG_d_string_callback = callback;
}


/* Contract support. */
#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_DSetPendingException(SWIG_DException, msg); return nullreturn; } else


#ifdef __cplusplus
extern "C" {
#endif


Code:
SWIGEXPORT int D_H3DRootNode_get() {
  int jresult ;
  H3DNode result;
 
  result = (H3DNode)(H3DNode)H3DRootNode;
  jresult = result;
  return jresult;
}


SWIGEXPORT void * D_new_H3DOptions() {
  void * jresult ;
  struct H3DOptions *result = 0 ;
 
  result = (struct H3DOptions *)calloc(1, sizeof(struct H3DOptions));
  jresult = (void *)result;
  return jresult;
}


SWIGEXPORT void D_delete_H3DOptions(void * jarg1) {
  struct H3DOptions *arg1 = (struct H3DOptions *) 0 ;
 
  arg1 = (struct H3DOptions *)jarg1;
  free((char *) arg1);
}

Code:
SWIGEXPORT char * D_h3dGetResName(int jarg1) {
  char * jresult ;
  H3DRes arg1 ;
  char *result = 0 ;
 
  arg1 = (H3DRes)jarg1;
  result = (char *)h3dGetResName(arg1);
  jresult = SWIG_d_string_callback((const char *)result);
  return jresult;
}


SWIGEXPORT int D_h3dGetNextResource(int jarg1, int jarg2) {
  int jresult ;
  int arg1 ;
  H3DRes arg2 ;
  H3DRes result;
 
  arg1 = (int)jarg1;
  arg2 = (H3DRes)jarg2;
  result = (H3DRes)h3dGetNextResource(arg1,arg2);
  jresult = result;
  return jresult;
}


SWIGEXPORT int D_h3dFindResource(int jarg1, char * jarg2) {
  int jresult ;
  int arg1 ;
  char *arg2 = (char *) 0 ;
  H3DRes result;
 
  arg1 = (int)jarg1;
  arg2 = (char *)jarg2;
  result = (H3DRes)h3dFindResource(arg1,(char const *)arg2);
  jresult = result;
  return jresult;
}


SWIGEXPORT int D_h3dAddResource(int jarg1, char * jarg2, int jarg3) {
  int jresult ;
  int arg1 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;
  H3DRes result;
 
  arg1 = (int)jarg1;
  arg2 = (char *)jarg2;
  arg3 = (int)jarg3;
  result = (H3DRes)h3dAddResource(arg1,(char const *)arg2,arg3);
  jresult = result;
  return jresult;
}


SWIGEXPORT int D_h3dCloneResource(int jarg1, char * jarg2) {
  int jresult ;
  H3DRes arg1 ;
  char *arg2 = (char *) 0 ;
  H3DRes result;
 
  arg1 = (H3DRes)jarg1;
  arg2 = (char *)jarg2;
  result = (H3DRes)h3dCloneResource(arg1,(char const *)arg2);
  jresult = result;
  return jresult;
}


SWIGEXPORT int D_h3dRemoveResource(int jarg1) {
  int jresult ;
  H3DRes arg1 ;
  int result;
 
  arg1 = (H3DRes)jarg1;
  result = (int)h3dRemoveResource(arg1);
  jresult = result;
  return jresult;
}


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 12.03.2011, 10:08 
Offline

Joined: 10.07.2009, 21:16
Posts: 42
This seems to generate some odd code ("result = (H3DNode)(H3DNode)H3DRootNode;" ?), and actually D is natively compatible with C (just have to rewrite the function prototypes).

I'm not sure about the advantages of a dependency on SWIG, as the current scripts will keep working as long as the style of the Horde3D headers does not change.

Apparently, SWIG generates a wrapper library?


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 12.03.2011, 16:33 
Offline

Joined: 15.09.2010, 18:31
Posts: 53
Funto wrote:
Apparently, SWIG generates a wrapper library?


Yes, SWIG is a wrapper generator, and code that i posted is a wrapper code. And this is excerpt from SWIG manual addressing to D:
Quote:
(...) Why would a SWIG module for D be needed then in the first place?
Well, besides the obvious downside that the C header files have to be manually converted to D modules for this to work, there is one major inconvenience with this approach: D code usually is on a higher abstraction level than C, and many of the features that make D interesting are simply not available when dealing with C libraries, requiring you e.g. to manually convert strings between pointers to \0-terminated char arrays and D char arrays, making the algorithms from the D2 standard library unusable with C arrays and data structures, and so on.
(...)



Funto wrote:
I'm not sure about the advantages of a dependency on SWIG, as the current scripts will keep working as long as the style of the Horde3D headers does not change.

Firstly, I'd like to specify, that I'm talking about optional dependency (activated by CMAKE switch) for those who are interested. Why I'd like to add this? Personally, I find lack of const annoying. Other reasons are pointed in quote above. Lastly, writing header converter script for each library looks odd to me, and i couldn't find good converter for D2. I'm not sure about wrapper costs though.


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 19.03.2011, 00:17 
Offline

Joined: 15.09.2010, 18:31
Posts: 53
Dirty and partial solution would be something like:
Code:
Index: trunk/Horde3D/Bindings/CMakeLists.txt
===================================================================
--- trunk/Horde3D/Bindings/CMakeLists.txt       (revision 724)
+++ trunk/Horde3D/Bindings/CMakeLists.txt       (working copy)
@@ -1 +1,2 @@
-add_subdirectory(C++)
\ No newline at end of file
+add_subdirectory(C++)
+add_subdirectory(D)

Code:
# ls D
CMakeLists.txt  derelict  native  swig
#cat CMakeLists.txt
add_subdirectory(swig)
# cd D && ls swig
CMakeLists.txt  Horde3D.i
# cat CMakeLists.txt
FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})

SET(CMAKE_SWIG_FLAGS "-d2")

aux_source_directory(${Horde3D_SOURCE_DIR}/Horde3D/Source/Horde3DEngine/ HORDE3D_SOURCES)
include_directories(${Horde3D_SOURCE_DIR}/Horde3D/Source/Horde3DEngine/ ${Horde3D_SOURCE_DIR}/Horde3D/Source/Shared/ ${Horde3D_SOURCE_DIR}/Extensions)

SET_SOURCE_FILES_PROPERTIES(Horde3D.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(Horde3D.i PROPERTIES SWIG_FLAGS "-wrapperlibrary Horde3D -includeall")
SET(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR})
SWIG_ADD_MODULE(Horde3D_wrap d Horde3D.i ${HORDE3D_SOURCES})
SWIG_LINK_LIBRARIES(Horde3D_wrap Horde3D)
SET_TARGET_PROPERTIES(Horde3D_wrap PROPERTIES LINKER_LANGUAGE C)

if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")

if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
        install(FILES Horde3D.d #Horde3DUtils.d
        DESTINATION include/d)
        install(TARGETS Horde3D_wrap
                RUNTIME DESTINATION bin
                LIBRARY DESTINATION lib
                ARCHIVE DESTINATION lib)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")

if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# cat Horde3D.i
%module Horde3D
%{
#include "../../C++/Horde3D.h"
%}
%include "../../C++/Horde3D.h"


Because noone answered, i need to firstly check performance difference on my own and then if it's worth to use this wrapper then i'll finalize SWIG integration in form of complete patch. Currently, i need to make something else so i'll post patch in this thread later.


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 19.03.2011, 12:16 
Offline

Joined: 10.07.2009, 21:16
Posts: 42
Ok, so the advantage of your system is to have a binding more "D-friendly" if I understand correctly (mainly regarded to strings and const, right?)
So I don't understand, your code mentions for example this function:
Code:
SWIGEXPORT char * D_h3dGetResName(int jarg1)

But it exports a char* and not a string. Is this code D or C code? I have no idea how SWIG works sorry ^^

BTW, do you happen to know if D 2.0 is stable now? The use of const, along with the fact that Bullet doesn't support D, are the 2 factors which made me switch back to C++.


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 19.03.2011, 19:31 
Offline

Joined: 15.09.2010, 18:31
Posts: 53
Funto wrote:
Ok, so the advantage of your system is to have a binding more "D-friendly" if I understand correctly (mainly regarded to strings and const, right?)


Well, it's not my system (I'm not author of D module of SWIG nor CMake module) but yes, it's more D-friendly. I should say more clearly about code i posted. SWIG is a wrapper generator, and code i posted is sample from C++ wrapper.
Sample function call would be:
Horde3D.d:
Code:
string h3dGetResParamStr(int res, int elem, int elemIdx, int param) {
  string ret = std.conv.to!string(Horde3D_im.h3dGetResParamStr(res, elem, elemIdx, param));
  return ret;
}


Horde3DD_wrap.cxx:
Code:
SWIGEXPORT char * D_h3dGetResParamStr(int jarg1, int jarg2, int jarg3, int jarg4) {
  char * jresult ;
  H3DRes arg1 ;
  int arg2 ;
  int arg3 ;
  int arg4 ;
  char *result = 0 ;

  arg1 = (H3DRes)jarg1;
  arg2 = (int)jarg2;
  arg3 = (int)jarg3;
  arg4 = (int)jarg4;
  result = (char *)h3dGetResParamStr(arg1,arg2,arg3,arg4);
  jresult = SWIG_d_string_callback((const char *)result);
  return jresult;
}


Whether it's performance ruining - needs to be judged.

Funto wrote:
BTW, do you happen to know if D 2.0 is stable now? The use of const, along with the fact that Bullet doesn't support D, are the 2 factors which made me switch back to C++.

From my experience - not really, but i like D 2.0 features so far, that i'm planning to go directly this way. The reason i encountered so many bugs is probably maximized use of newest features. Others are saying, that they're using D2.0, but as 'better D1', and they had absolutely no problem with bugs.

About bullet, I didn't used it yet, but http://code.google.com/p/bullet/issues/detail?id=43 might interest You.


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 26.03.2011, 12:04 
Offline

Joined: 10.07.2009, 21:16
Posts: 42
Yes I'm wondering how such a wrapper affects performance...In the end, this creates 2 layers between the core engine and the user code (as the Horde C API is already a layer between both).
Another possibility would be maybe to directly write a D API, as is done with Horde C API, as I know there is some support for communication with C++ in D 2.0 - though I don't know what the possibilities really are.

About the Bullet C API, it is actually a part of Bullet itself, but I don't think it is actively maintained.

I just had a quick look at Bullet-C-Api.h, and for example, there is no reference to the soft body engine.

Furthermore, one can read the following at the beginning of Bullet-C-Api.h :
Code:
/*
   Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's.
   Work in progress, functionality will be added on demand.

   If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h"
*/


Top
 Profile  
Reply with quote  
 Post subject: Re: Horde3D with SWIG?
PostPosted: 26.03.2011, 14:42 
Offline

Joined: 15.06.2008, 11:21
Posts: 166
Location: Germany
Quote:
Yes I'm wondering how such a wrapper affects performance

I am quite certain this performance hit will not be measurable in normal use cases. I mean, how many calls to h3d are you making every frame, and how much is the difference between call overhead and the called h3d function? For some hundred function calls you won't feel a difference.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 13 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group