Closed mastercuber55 closed 1 year ago
btw Being able to call those functions directly without class will also work for me.
Hi @mastercuber55
Unfortunately having purely global functions is not supported. However, you could do the following:
Create a dummy class on the C++ side. It does not have to define anything. You can leave it blank.
class RayLib {
};
Then register any ray lib functions. Something like this should work:
// Assuming this global function is from raylib
extern void DrawRectangle(int x, int y, int w, int h, int color);
wren::VM vm;
auto& m = vm.module("mymodule");
auto& cls = m.klass<RayLib>("RayLib"); // Dummy
cls.funcStaticExt<&DrawRectangle>("DrawRectangle"); // Here, use "funcStaticExt"
But that would force you to create an instance of RayLib
class in the Wren user code. There is one trick for that! Create an instance of the RayLib
in Wren
and make it a global variable (has to start with an upper case letter):
m.append("var RL = RayLib.new()\n");
The m.append
appends any kind of Wren code into the module you have created with vm.module("mymodule")
.
Then, in your Wren user code, you can do this:
import "mymodule" for RL
RL.DrawRectangle(10, 20, 100, 200, 255)
A similar concept is here: https://matusnovak.github.io/wrenbind17/tutorial/custom_types/#656-class-static-variables (section "6.5.6 Class static variables").
Would this little hack work for you?
Hi matsunovak, thank you for writing a example for me and yes it will work for me so thank you once again.
I'm unforunately unable to get it working, I'm getting this wrenbind17::CompileError
on running my wren code
terminate called after throwing an instance of 'wrenbind17::CompileError'
what(): Runtime error: raylib does not implement 'InitWindow(_,_,_)'.
at: wrenbind17.wren:3
Here's the wren code
import "raylib" for rl
rl.InitWindow(640, 480, "Hello Wren")
and here is the code on c++ side
auto& Raylibm = VM.module("raylib");
auto& Raylibc = Raylibm.klass<raylib>("raylib");
Raylibc.ctor<>();
Raylibc.funcStaticExt<&InitWindow>("InitWindow");
Raylibm.append("var rl = raylib.new()\n");
and this is the raylib function
RLAPI void InitWindow(int width, int height, const char *title);
Oh! My bad! I told you to create an instance but to use a static function :D I probably should not write code at midnight.
So, problem number one, the raylib does not implement
is because Wren is looking for a function with 4 parameters where the first one is "this" an instance of the class and the 3 other parameters x, y, and the title. I gave you a wrong code.
Problem number two is that you can't use const char*
in the function arguments. Wren is the owner of the strings, so taking a pointer out of them and using it in a C++ class is dangerous and can cause segmentation fault. Therefore I have not implemented that conversion into this library on purpose. You have to create a wrapper function that accepts std::string
and calls the real RayLib function with .c_str()
.
Therefore, you need something like this:
// This should be the real RayLib function, for the purpose of this example
// I am just defining it here like this to print out the arguments.
static void InitWindow(int x, int y, const char* title) {
std::cout << "InitWindow called with x: " << x << " y: " << y << " title: " << title << std::endl;
}
// A wrapper class
class Raylib {
public:
// A function that accepts std::string instead of const char
static void wrenInitWindow(int x, int y, const std::string& title) {
// Call the real RayLib function with the const char* from the std::string
// It assumes that RayLib's function InitWindow() makes a copy of the const char*
// Otherwise there will be a segmentation fault at some point later.
InitWindow(x, y, title.c_str());
}
};
int main() {
wren::VM vm;
auto& m = vm.module("raylib");
auto& cls = m.klass<Raylib>("RL");
// Bind the custom function, not the real InitWindow.
cls.funcStaticExt<&Raylib::wrenInitWindow>("InitWindow");
// Sample code to run
static const std::string code = R"(
import "raylib" for RL
RL.InitWindow(640, 480, "Hello Wren")
)";
vm.runFromSource("main", code);
return 0;
}
Should print:
InitWindow called with x: 640 y: 480 title: Hello Wren
An alternative version, not using static functions, but creating an instance of the wrapper class.
static void InitWindow(int x, int y, const char* title) {
std::cout << "InitWindow called with x: " << x << " y: " << y << " title: " << title << std::endl;
}
class Raylib {
public:
void wrenInitWindow(int x, int y, const std::string& title) { // No longer static
InitWindow(x, y, title.c_str());
}
};
int main() {
wren::VM vm;
auto& m = vm.module("raylib");
auto& cls = m.klass<Raylib>("Raylib");
cls.ctor<>(); // Added empty constructor
cls.func<&Raylib::wrenInitWindow>("InitWindow"); // Changed from "funcStaticExt" to "func"
m.append("var RL = Raylib.new()\n"); // Added
// Remains the same
const std::string code = R"(
import "raylib" for RL
RL.InitWindow(640, 480, "Hello Wren")
)";
vm.runFromSource("main", code);
return 0;
}
Tested on my PC, should work out of the box.
Yea, that worked so thanks again a bunch and I hope I don't have to reopen this issue and bother you anymore.
btw I think you make a discord server for this amazing library.
Yea, that worked so thanks again a bunch and I hope I don't have to reopen this issue and bother you anymore.
No problem. Feel free to ask for more help.
btw I think you make a discord server for this amazing library.
Good idea but I do not want to manage a Discord server :D Too much work. GitHub issues seem easier to me.
I'm using a graphics library called raylib It defines a bunch of functions.
on wren side I want to put all of those raylib functions inside a class named "rl" without defining any wrapper classes to call those functions on c++ side
but I was unable to find anything about this in Tutorials section.