blitz types to c++?
Blitz3D Forums/Blitz3D Programming/blitz types to c++?
| ||
I am wondering if anyone knew about this before, and if there is a better way to do it? c++ header file: class test { public: int x,y,z; float a,b; }; c++ cpp file: #include <stdlib.h> #include <math.h> //the header file #include "testing.h" #define BBDECL extern "C" _declspec(dllexport) #define BBCALL _stdcall BBDECL void BBCALL boo(test* obj) { obj->a = 5.6f; obj->x = 4; obj->y = 5; obj->z = 6; obj->b = 10.9f; } the decls file in userlibs: .lib "testing.dll" boo(obj*):"_boo@4" the blitz file: Type test Field x,y,z Field a#,b# End Type t.test = New test boo(t) Print(t\a) Print(t\b) Print(t\x) Print(t\y) Print(t\z) waitkey() end c++ code compiled in visual c++ 2005 express edition. I am not sure if you can return a c++ class, all I have tried is passing a blitz type into the c++ class. Lego is the best... |
| ||
Is this method slower than poking/peeking from banks to send multiple amounts of data (it is sure easier!)? |
| ||
You can even send arrays, and set up double linked lists on both sides to loop through them(in c++ or blitz!) |
| ||
What are the ramifications to using this? Doesn't work in debug mode because there Blitz checks for array bounds... c++ cpp file: #include <stdlib.h> #include <math.h> //the header file #include "testing.h" #define BBDECL extern "C" _declspec(dllexport) #define BBCALL _stdcall class test { public: int* temp; }; BBDECL void BBCALL boo(test* obj) { obj->temp = (int*) malloc(sizeof(int) * 500); for(int i=0;i<500;i++) { obj->temp[i] = 4; } } blitz code: Graphics 800,600,0,2 Type test Field temp[100] End Type t.test = New test boo(t) For i = 0 To 499 Print(t\temp[i]) Next WaitKey() End (uses same decls as above) I am sure somewhere there is a memory leak...is there any way to get blitz debugging to work with this? |
| ||
This is a very interesting topic. I didn't knew you could send types to a .dll. That could be very handy. In the last post, why do you set the temp field length to [100]? Shouldn't it be 500? |
| ||
The whole point was that the c++ code is able to resize the blitz arrays, perhaps dynamically... and Blitz in non-debugger mode doesn't really seem to care. There's probably a catch somewhere, though...like that it doesn't work in debug mode :( The idea is maybe you could return any amount of data, resizing the arrays in the c++ data. You could perhaps have in the type an int telling how big the array is, then simply access it from blitz. ...I guess all I am after is a way to return any amount of data from a dll in one call without knowing how many before hand, but simply let the dll return the right amount and a reference to how much that is. |
| ||
Interesting stuff! perhaps dynamically Definitely dynamically. Pretty hard to do something that's not dynamic with a Dynamically Linked Library. ;) I am sure somewhere there is a memory leak Yeah, you need to free() your malloc()ed memory. I also imagine that Blitz will use the array pointer to free the original 100 element array, so you should also revert the pointer to its original value before letting Blitz delete the object. Of course, if your objects will stay alive until your program ends, you can just forget about leaks and let the OS clean up after you. If you want to trick the Blitz debugger, I would think this might work: Type packet Field foo#, bar% End Type Type result Field p.packet[1000000000] ; just to fool Blitz's bounds checker (C++, not Blitz, will instantiate result objects) Field max_packets% End Type Local r.result = get_data() ; call c++ For i% = 0 To r\max_packets - 1 Local p.packet = r\p[i] Print "got a packet: foo=" + p\foo + " bar=" + p\bar Next free_data(r) ; call c++ to clean up struct packet { float foo; int bar; }; struct result { packet * packet_ptr; int max_packets; }; BBDECL result * BBCALL get_data() { result * r = new result; // create some arbitrary packets r->max_packets = 42; r->packet_ptr = (packet*) malloc(sizeof(packet) * 42); for(int i=0;i<42;i++) { r->packet_ptr[i].foo = 6.02f; r->packet_ptr[i].bar = i; } return(r); } BBDECL void BBCALL free_data(result * r) { free(r->packet_ptr); delete(r); } Because you're relying on C++ to create the "result" object, Blitz won't ever try to allocate 1000000000 packets. At the same time, the Blitz debugger assumes that any existing "result" objects will have been created with a nice big fat array and won't mind if you dereference elements with indices below 1000000000. This leaves the responsibility of bounds checking in Blitz up to you. Note that objects created in C++ won't be added to Blitz's builtin linked-lists so you won't be able to use First, After, etc. P.S. "class test { public:" is the same as "struct test {" |
| ||
Octothorpe, I am having trouble getting your version to work, I cannot figure out in the decls file how to tell blitz that it is returning an object...all I have managed to do is make the blitzcc.exe completely crash, having to restart my computer, or get error messages... |
| ||
I don't know anything about decls files, but if you're unable to return an object pointer from C++, how about passing in an object with a pointer field and modifying the pointer?Type result_wrapper Field r.result End Type Local rw.result_wrapper = New result_wrapper get_data(rw) ; call C++ Local r.result = rw\r ; then do the same as before struct result_wrapper { result * r; }; BBDECL void BBCALL get_data(result_wrapper * rw) { rw->r = new result; //etc Make sense? |
| ||
... Blitz creates an unhandled memory exception when you try to create a type in c++....It is looking like blitz does some special conversion of its types in order to send it to c++, and does not work with creating types in c++. :( |
| ||
Hmm, that sucks. Sorry about the wild goose chase. One hack that should work and make the Blitz debugger happy would be if you added another C++ function to your original code which advances your array pointer. You'd only be able to reference N (100 in your example above) elements at a time, but could move the pointer forward to the next N when you finish with them. BBDECL void BBCALL advance_ptr(test* obj) { obj->temp = obj->temp + 100; } |
| ||
Totally unsafe and crazy:b = CreateBank() PokeByte(b, -16, 255) Print PeekByte(b, 254) Maybe with some research you could modify the bounds of a bank safely from C++? I'd be worried that outside of debug mode, banks might not have that header and you'd be writing all over other data. |
| ||
Yeah, I've already tried that...writing in c++ writes the bytes to different locations, so trying to read them back in blitz returns a garbled mess. Also, I was thinking about having a function return the size of the data, and then have blitz resize a bank to that size and pass it to another function which fills it. This should work, but I have not tried implementing it yet. |
| ||
sorry to drag this back, but is there a faster to way to get function pointers in blitz with arguments than this? c++ code // a function pointer declaration for calling Blitz3D code void (__stdcall *ABlitz3DFunction)(void); class passer { public: int t,h; float b,s; }; passer pass; #define BBDECL extern "C" _declspec(dllexport) #define BBCALL _stdcall // standard DLL function declaration for Blitz3D userlibs BBDECL void BBCALL SetBlitz3DFunction(void) { unsigned int stackpos,adrs; unsigned int *func; __asm { mov stackpos,esp mov esp,ebp add esp,4 pop adrs mov esp,stackpos } func=(unsigned int*)&ABlitz3DFunction; *func=adrs; } // extra DLL function for test purposes only - your DLL would call ABlitz3DFunction() directly! BBDECL void BBCALL CallBlitz3DFunction(void) { //"pass" arguments into the function pass.t = 6; pass.s = 7.8f; pass.b = 5.2f; pass.h = 8; ABlitz3DFunction(); } BBDECL void BBCALL Get_Args(passer* p) { p->t = pass.t; p->h = pass.h; p->s = pass.s; p->b = pass.b; } blitz code: Global SETUP_FUNCS%=1 Gosub test_function SETUP_FUNCS=0 CallBlitz3DFunction() ;<-- testing DLL access only WaitKey End .test_function SetBlitz3DFunction() If SETUP_FUNCS=0 p.passer = New passer GET_Args(p) ABlitz3DFunction(p\t,p\h,p\s,p\b) EndIf Return Function ABlitz3DFunction(t,h,s#,b#) ; *** function body goes here!!! Print "This works!!!!"+t+h+s+b Return End Function Type passer Field t,h,b#,s# End Type it is probably a little messy still, but the idea is there. Have c++ call the blitz code, which responds by asking c++ what the arguments are, and then calls the necessary function. Also, I have not clocked it to see how fast it is, but I am assuming that it is not unmanageably slow. edit: after timing it looping through 2 million times (without print command) it took it just over 1 second. with 2000 times it took 1 millisecond. Compare that to the 602 millisecs it takes to make a function call within blitz wile passing one parameter 2 million times. :) |