1. Orx Wrapper Hurdles

Hello all,

As I was writing the wrapper for Orx I came across the most obvious hurdle. The init and execute functions needed for Orx are not in the Orx DLL as they are called as Inline functions and not exported to the DLL. So without those, Orx won't start even with other commands that have init functions. There may be a way with ifdef statements, but I haven't tried yet. If anyone could help or has a solution, please let me know. Otherwise I'm not sure how feasible this wrapper may be to continue.

https://orx-project.org/orx/doc/html/orx_8h_source.html

static orxINLINE void orx_Execute(orxU32 _u32NbParams, orxSTRING _azParams[], const orxMODULE_INIT_FUNCTION _pfnInit, const orxMODULE_RUN_FUNCTION _pfnRun, const orxMODULE_EXIT_FUNCTION _pfnExit) 

ifdef orx_Eexcute then 
   --I'm not sure how to trasnalte this to eu code 
end ifdef 

I already have some functions already wrapped.

public constant xorxClock_Setup = define_c_proc(orx,"+orxClock_Setup",{}), 
				xorxClock_Init = define_c_func(orx,"+orxClock_Init",{},C_UINT), 
				xorxClock_Exit = define_c_proc(orx,"+orxClock_Exit",{}) 
 
public procedure orxClock_Setup() 
 
 c_proc(xorxClock_Setup,{}) 
	 
end procedure 
 
public function orxClock_Init() 
 
 return c_func(xorxClock_Init,{}) 
	 
end function 
 
public procedure orxClock_Exit() 
 
 c_proc(xorxClock_Exit,{}) 
	 
end procedure 
 
new topic     » topic index » view message » categorize

2. Re: Orx Wrapper Hurdles

Icy_Viking said...

Hello all,

As I was writing the wrapper for Orx I came across the most obvious hurdle. The init and execute functions needed for Orx are not in the Orx DLL as they are called as Inline functions and not exported to the DLL. So without those, Orx won't start even with other commands that have init functions. There may be a way with ifdef statements, but I haven't tried yet. If anyone could help or has a solution, please let me know. Otherwise I'm not sure how feasible this wrapper may be to continue.

I mentioned this in your original thread: https://openeuphoria.org/forum/136281.wc#136281

ghaberek said...

Two major hurdles I'm seeing here:

  • Calling convention: Most of the library functions are declared using the fastcall convention, which Euphoria isn't currently built to handle (we only support stdcall and cdecl). It's possible this might only be the case when compiling the library statically so that it's embedded into the resulting executable and the shared library might still be using stdcall or cdecl. I haven't dug through the code enough to tell yet. The good news is that all those different conventions only affect x86 and on x64 there's just "the x64 calling convention" so it should work fine if you stick to 64-bit Euphoria (which you should!).

  • Inline functions: Some functions of the library are declared inline which means they're always compiled directly into the executable and don't get exported (or even compiled into) the shared library. You could either unmark these as inline and rebuild the library or reconstruct them directly in Euphoria. Unfortunately the orx_Execute function is marked inline, and it's literally the first function you need to bootstrap a program.

Obviously you've solved the calling convention issue, great job! It looks like these functions are declared with both static and orxINLINE which is a bit problematic. The orxINLINE is guarded in an ifndef block so defining that as blank (-DorxINLINE) should stop it from inserting inline everywhere, but there's no corresponding orxSTATIC and the static keyword is just used directly in the code. So if you wanted to fix this you'd have to copy the ifndef block for orxINLINE to orxSTATIC and then do the same trick of defining it as blank.

My recommendation would be to just rewrite these functions directly in Euphoria. It seems like they're marked static and inline because they're small, so doing so shouldn't be difficult. Doing this will also give you the benefit of allowing the interpreter to inline the routines, keeping with the intent of the original code. The default behavior is to inline routines of 30 IL bytes. You can override this with with inline. So if you can figure out how many IL bytes these routines use (using dis.ex maybe?) then you can manually tweak that value in the wrapper file.

-Greg

new topic     » goto parent     » topic index » view message » categorize

3. Re: Orx Wrapper Hurdles

ghaberek said...
Icy_Viking said...

Hello all,

As I was writing the wrapper for Orx I came across the most obvious hurdle. The init and execute functions needed for Orx are not in the Orx DLL as they are called as Inline functions and not exported to the DLL. So without those, Orx won't start even with other commands that have init functions. There may be a way with ifdef statements, but I haven't tried yet. If anyone could help or has a solution, please let me know. Otherwise I'm not sure how feasible this wrapper may be to continue.

I mentioned this in your original thread: https://openeuphoria.org/forum/136281.wc#136281

ghaberek said...

Two major hurdles I'm seeing here:

  • Calling convention: Most of the library functions are declared using the fastcall convention, which Euphoria isn't currently built to handle (we only support stdcall and cdecl). It's possible this might only be the case when compiling the library statically so that it's embedded into the resulting executable and the shared library might still be using stdcall or cdecl. I haven't dug through the code enough to tell yet. The good news is that all those different conventions only affect x86 and on x64 there's just "the x64 calling convention" so it should work fine if you stick to 64-bit Euphoria (which you should!).

  • Inline functions: Some functions of the library are declared inline which means they're always compiled directly into the executable and don't get exported (or even compiled into) the shared library. You could either unmark these as inline and rebuild the library or reconstruct them directly in Euphoria. Unfortunately the orx_Execute function is marked inline, and it's literally the first function you need to bootstrap a program.

Obviously you've solved the calling convention issue, great job! It looks like these functions are declared with both static and orxINLINE which is a bit problematic. The orxINLINE is guarded in an ifndef block so defining that as blank (-DorxINLINE) should stop it from inserting inline everywhere, but there's no corresponding orxSTATIC and the static keyword is just used directly in the code. So if you wanted to fix this you'd have to copy the ifndef block for orxINLINE to orxSTATIC and then do the same trick of defining it as blank.

My recommendation would be to just rewrite these functions directly in Euphoria. It seems like they're marked static and inline because they're small, so doing so shouldn't be difficult. Doing this will also give you the benefit of allowing the interpreter to inline the routines, keeping with the intent of the original code. The default behavior is to inline routines of 30 IL bytes. You can override this with with inline. So if you can figure out how many IL bytes these routines use (using dis.ex maybe?) then you can manually tweak that value in the wrapper file.

-Greg

Hi Greg, thanks for the input. This is where the problem lies. I'm not sure how to translate the inline functions into Eu code. I have vague ideas, but I'm really stuck as to where to go from there.

new topic     » goto parent     » topic index » view message » categorize

4. Re: Orx Wrapper Hurdles

Icy_Viking said...

Hi Greg, thanks for the input. This is where the problem lies. I'm not sure how to translate the inline functions into Eu code. I have vague ideas, but I'm really stuck as to where to go from there.

Here's a quick conversion of 01_Object.c.

include "orx.e" 
 
/** Inits the tutorial */ 
function Init() 
 
    /* Displays a small hint in console */ 
    orxLOG("\n* This tutorial creates a viewport/camera couple and an object" 
         & "\n* You can play with the config parameters in ../01_Object.ini" 
         & "\n* After changing them, relaunch the tutorial to see their effects") 
 
    /* Creates viewport */ 
    orxViewport_CreateFromConfig("Viewport") 
 
    /* Creates object */ 
    orxObject_CreateFromConfig("Object") 
 
    /* Done! */ 
    return orxSTATUS_SUCCESS 
end function 
 
/** Run function */ 
function Run() 
 
    integer eResult = orxSTATUS_SUCCESS 
 
    /* Should quit? */ 
    if orxInput_IsActive("Quit") then 
 
        /* Updates result */ 
        eResult = orxSTATUS_FAILURE 
 
    end if 
 
    /* Done! */ 
    return eResult 
end function 
 
/** Exit function */ 
function Exit() 
 
    /* We're a bit lazy here so we let orx clean all our mess! :) */ 
 
    return 0 
end function 
 
/** Main function */ 
procedure main() 
 
    sequence argv = command_line() 
    integer argc = length(argv) 
 
    /* Executes a new instance of tutorial */ 
    orx_Execute(argc, argv, "Init", "Run", "Exit") 
 
end procedure 
 
main() 

Most of this hinges on orx_Execute which is of course inline, so here's how I'd (roughly) convert it:

/** Should stop execution by default event handling? */ 
integer sbStopByEvent = orxFALSE 
 
/** Orx main execution function 

 * @param[in]   _u32NbParams                  Main function parameters number (argc) 
 * @param[in]   _azParams                     Main function parameter list (argv) 
 * @param[in]   _pfnInit                      Main init function (should init all the main stuff and register the main event handler to override the default one) 
 * @param[in]   _pfnRun                       Main run function (will be called once per frame, should return orxSTATUS_SUCCESS to continue processing) 
 * @param[in]   _pfnExit                      Main exit function (should clean all the main stuff) 
 */ 
public procedure orx_Execute(atom _u32NbParams, sequence _azParams, sequence _zInit, sequence _zRun, sequence _zExit, integer _fnInit=routine_id(_zInit), integer _fnRun=routine_id(_zRun), integer _fnExit=routine_id(_zExit)) 
 
    /* Inits the Debug System */ 
    orxDEBUG_INIT() 
 
    /* Checks */ 
    orxASSERT(_u32NbParams > 0) 
    orxASSERT(_azParams != orxNULL) 
    orxASSERT(_fnRun != orxNULL) 
 
    /* Registers main module */ 
    orxModule_Register(orxMODULE_ID_MAIN, "MAIN", routine_id("orx_MainSetup"), _fnInit, _fnExit) 
 
    /* Sends the command line arguments to orxParam module */ 
    if orxParam_SetArgs(_u32NbParams, _azParams) != orxSTATUS_FAILURE then 
 
        /* Inits the engine */ 
        if orxModule_Init(orxMODULE_ID_MAIN) != orxSTATUS_FAILURE then 
 
            atom stPayload = allocate_data( SIZEOF_ORXSYSTEM_EVENT_PAYLOAD ) 
            integer eClockStatus, eMainStatus 
            integer bStop = orxFALSE 
            atom u32FrameCount 
 
            /* Registers default event handler */ 
            orxEvent_AddHandler(orxEVENT_TYPE_SYSTEM, orx_DefaultEventHandler) 
            orxEvent_SetHandlerIDFlags(orx_DefaultEventHandler, orxEVENT_TYPE_SYSTEM, orxNULL, orxEVENT_GET_FLAG(orxSYSTEM_EVENT_CLOSE), orxEVENT_KU32_MASK_ID_ALL) 
 
            /* Clears payload */ 
            orxMemory_Zero(stPayload, SIZEOF_ORXSYSTEM_EVENT_PAYLOAD) 
 
            /* Main loop */ 
            while bStop = orxFALSE do 
 
                /* Sends frame start event */ 
                orxEVENT_SEND(orxEVENT_TYPE_SYSTEM, orxSYSTEM_EVENT_GAME_LOOP_START, orxNULL, orxNULL, stPayload) 
 
                /* Runs game specific code */ 
                eMainStatus = call_func( _fnRun, {} ) 
 
                /* Updates clock system */ 
                eClockStatus = orxClock_Update() 
 
                /* Sends frame stop event */ 
                orxEVENT_SEND(orxEVENT_TYPE_SYSTEM, orxSYSTEM_EVENT_GAME_LOOP_STOP, orxNULL, orxNULL, stPayload) 
 
                /* Updates frame count */ 
                u32FrameCount = peek4u( stPayload + orxSYSTEM_EVENT_PAYLOAD_u32FrameCount ) 
                poke4( stPayload + orxSYSTEM_EVENT_PAYLOAD_u32FrameCount, u32FrameCount + 1 ) 
 
                bStop = ((sbStopByEvent != orxFALSE) or (eMainStatus = orxSTATUS_FAILURE) or (eClockStatus = orxSTATUS_FAILURE)) 
            end while 
 
            /* Removes event handler */ 
            orxEvent_RemoveHandler(orxEVENT_TYPE_SYSTEM, orx_DefaultEventHandler) 
 
            /* Exits from the engine */ 
            orxModule_Exit(orxMODULE_ID_MAIN) 
 
            free( stPayload ) 
 
        end if 
 
    end if 
 
    /* Exits from the Debug system */ 
    orxDEBUG_EXIT() 
 
end procedure 

-Greg

new topic     » goto parent     » topic index » view message » categorize

5. Re: Orx Wrapper Hurdles

Thanks Greg, this has made it much more clear.

Here's what I have so far. Note that orxASSERT is not wrapped yet, orxDefaultEventHandler and orxEventPayloadSize are structs, so I haven't got around to wrapping/converting to them to Eu code yet. I guess I could release what I have wrapped so far and EuOrx can be a Euphoria community project kinda similar to how Win32lib was. Not sure how many would be interested in helping though.

--Memory Zero is an inline functions 
public procedure orxMemory_Zero(atom d,atom size) 
 
 d = 0 
 size = allocate_data(1000) 
	 
end procedure 
 
--Orx inline Functions converted to Eu 
 
integer sbStopByEvent = orxFALSE 
 
public procedure orx_Execute(atom _u32NbParams,sequence _azParams,sequence _zInit,sequence _zRun,sequence _zExit,integer _fnInit=routine_id(_zInit),integer _fnRun=routine_id(_zRun),integer _fnExit=routine_id(_zExit)) 
 
 orxDebug_Init() 
  
 --orxASSERT not wrapped yet 
  
 orxModule_Register(orxMODULE_ID_MAIN,"MAIN",routine_id("orx_MainSetup"),_fnInit,_fnExit) 
  
 if orxParam_SetArgs(_u32NbParams, _azParams) != orxSTATUS_FAILURE then 
 	 
	if orxModule_Init(orxMODULE_ID_MAIN) != orxSTATUS_FAILURE then 
		atom stPayload = allocate_data(1000) 
		integer eClockStatus,eMainStatus 
		integer bStop = orxFALSE 
		atom u32FrameCount 
		 
		orxEvent_AddHandler(orxEVENT_TYPE_SYSTEM, 1) 
		orxEvent_SetHandlerIDFlags(1,orxEVENT_TYPE_SYSTEM,orxNULL,orxEVENT_GET_FLAG=orxSYSTEM_EVENT_CLOSE, orxEVENT_KU32_MASK_ID_ALL) 
		 
        orxMemory_Zero(stPayload,allocate_data(1000)) 
         
 		while bStop = orxFALSE do 
 		 
 			orxEvent_Send(orxEVENT_TYPE_SYSTEM+orxSYSTEM_EVENT_GAME_LOOP_START+orxNULL+orxNULL+stPayload) 
 			 
			eMainStatus = call_func(_fnRun,{}) 
			eClockStatus = orxClock_Update() 
			 
			orxEvent_Send(orxEVENT_TYPE_SYSTEM+orxSYSTEM_EVENT_GAME_LOOP_STOP+orxNULL+orxNULL+stPayload) 
			 
			u32FrameCount = peek4u(stPayload + 1) 
			poke4(stPayload + orxEVENT_TYPE_SYSTEM,u32FrameCount + 1) 
			bStop = ((sbStopByEvent != orxFALSE) or (eMainStatus = orxSTATUS_FAILURE) or (eClockStatus = orxSTATUS_FAILURE)) 
 		end while 
 		 
       orxEvent_RemoveHandler(orxEVENT_TYPE_SYSTEM,1) 
        
		orxModule_Exit(orxMODULE_ID_MAIN) 
		 
		free(stPayload) 
	end if 
 
 end if 
  
  orxDebug_Exit() 
	 
end procedure 
new topic     » goto parent     » topic index » view message » categorize

6. Re: Orx Wrapper Hurdles

Icy_Viking said...

Here's what I have so far. Note that orxASSERT is not wrapped yet,

I've developed a few tricks when making Euphoria MVC's logging library that can contribute which should very similar behavior to how these debug macros work in Orx.

Icy_Viking said...

orxDefaultEventHandler and orxEventPayloadSize are structs, so I haven't got around to wrapping/converting to them to Eu code yet.

I haven't looked, but if there aren't too many structs in Orx then wrapping them the traditional way (a bunch of constants of field offsets) should be fine.

But if Orx makes heavy use of structs then using the new memstruct feature should prove helpful here. I'm getting pretty close on having a full build ready for 4.2. (Although that might still be "months" close not "days" close.)

Icy_Viking said...

I guess I could release what I have wrapped so far and EuOrx can be a Euphoria community project kinda similar to how Win32lib was. Not sure how many would be interested in helping though.

I would be happy to contribute. I already started exploring and semi-wrapping Orx to get a feel for how the library comes together. I can contribute the work I've done so far if you to share access to your repo.

-Greg

new topic     » goto parent     » topic index » view message » categorize

7. Re: Orx Wrapper Hurdles

ghaberek said...
Icy_Viking said...

Here's what I have so far. Note that orxASSERT is not wrapped yet,

I've developed a few tricks when making Euphoria MVC's logging library that can contribute which should very similar behavior to how these debug macros work in Orx.

Icy_Viking said...

orxDefaultEventHandler and orxEventPayloadSize are structs, so I haven't got around to wrapping/converting to them to Eu code yet.

I haven't looked, but if there aren't too many structs in Orx then wrapping them the traditional way (a bunch of constants of field offsets) should be fine.

But if Orx makes heavy use of structs then using the new memstruct feature should prove helpful here. I'm getting pretty close on having a full build ready for 4.2. (Although that might still be "months" close not "days" close.)

Icy_Viking said...

I guess I could release what I have wrapped so far and EuOrx can be a Euphoria community project kinda similar to how Win32lib was. Not sure how many would be interested in helping though.

I would be happy to contribute. I already started exploring and semi-wrapping Orx to get a feel for how the library comes together. I can contribute the work I've done so far if you to share access to your repo.

-Greg

That sounds great Greg! Also, excited to hear that Eu 4.2 is coming along nicely. Hopefully it will release before the end of this year. There's a handful of structs and unions in Orx, but it might be possible to convert them into Eu code using constants and such. I have started a repo for Orx on my current wrapper. So far left to do is finish wrapping the flags and functions from The I/O section of the game engine, starting with the file functions. I have commented in the code. I of course will be continung to work on this in the meantime. Anyone else who would like to help, please contact or say something in this thread. Let me know what section of the wrapper you'd like to work on and such.

The memstruct feature will help a ton when writing wrappers! I really hope you will be able to get it out before the end of this year.

What I do is go into the Orx help files and find the .h file for what I need to wrap and wrap the functions going down the .h file. For example I'd go into orxFile.h to continue wrapping the file functions for Orx. And then go from there.

@Greg, I've given you access/invited you to the EuOrx repo. Anyone else who wants to help, please contact me on here if you'd like access to the repo.

https://github.com/gAndy50/EuOrx - Repo

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu