无法将正确的 lambda 传递给 emscripten_set_main_loop
Unable to pass a proper lambda to emscripten_set_main_loop
我真的很难指示 emscripten_set_main_loop 执行渲染新帧的方法。我根本无法想出一个成功编译的 lambda,更不用说按预期运行了。
首先,我得到了 MyView
class,它应该作为 Javascript 的接口。这个想法是创建一个该类型的新对象,然后调用 StartRenderingLoop
这将启动渲染新帧的循环。这应该从 Javascript 开始,这就是为什么我在底部得到 Embind 定义的原因:
class MyView
{
public:
void StartRenderingLoop();
private:
std::unique_ptr<Renderer> _renderer;
void Render();
};
EMSCRIPTEN_KEEPALIVE
MyView::MyView()
{
_renderer = std::unique_ptr<Renderer>(new Renderer());
}
void MyView::Render()
{
_renderer->Render();
}
EMSCRIPTEN_KEEPALIVE
void MyView::StartRenderingLoop()
{
emscripten_set_main_loop(/* should invoke MyView::Render(), but how? */, -1, 1);
}
EMSCRIPTEN_BINDINGS(MyView)
{
class_<MyView>("MyView")
.function("startRenderingLoop", &MyView::StartRenderingLoop)
// everything else...
;
}
这是我尝试过的:
这甚至无法编译:
emscripten_set_main_loop(&MyView::Render(), -1, 1);
Emscripten 抛出以下错误:
note: candidate function not viable: no known conversion from 'void (MyView::*)()' to 'em_callback_func' (aka 'void (*)()') for 1st argument
不编译:
emscripten_set_main_loop([]() { _renderer->Render(); }, -1, 1);
因为它无法访问 this
指针,很公平:
error: 'this' cannot be implicitly captured in this context
捕获 this
使 lambda 与预期不兼容并抛出类似于尝试 1 的错误:
emscripten_set_main_loop([this]() { _renderer->Render(); }, -1, 1);
声明一个全局std::function
对象:
static std::function<void()> renderLoopFunction;
然后在 StartRenderingLoop
中做这样的事情:
EMSCRIPTEN_KEEPALIVE
void MyView::StartRenderingLoop()
{
renderLoopFunction = [=]() mutable { int test = 3; };
emscripten_set_main_loop(renderLoopFunction, -1, 1);
}
与 this 等资源相反,它再次编译失败:
note: candidate function not viable: no known conversion from 'std::function<void ()>' to 'em_callback_func' (aka 'void (*)()') for 1st argument
我正处于这样一个阶段,如果有一个拥有三个免费愿望的仙女出现,我很乐意将其中一个用于解决这个谜团,只是为了让编译器停止告诉我我是一个多么无能的白痴.
该接口需要类型为 void (*)()
的普通旧 c 函数指针。
假设您只打算拥有一个 Render
对象...
class MyView
{
public:
void Render();
private:
std::unique_ptr<Renderer> _renderer;
};
// a global or otherwise known globally
auto view = MyView();
// &main_loop has the signature void (*)(), which is what you need
void main_loop()
{
view.Render();
}
int main()
{
emscripten_set_main_loop(&main_loop, -1, 1);
}
似乎为了利用 emscripten_set_main_loop_arg
我真的不得不退回到使用 C。因为我更喜欢尽可能地保持代码面向对象,所以我正在寻找替代方案。事实证明,该函数的第二个版本能够处理参数:emscripten_set_main_loop_arg
.
使用 emscripten_set_main_loop_arg
我可以将 StartRenderingLoop
方法保留为实例方法,只需将 this
传递给 Render
回调。修改后的代码如下:
void MyView::Render()
{
_renderer->Render();
}
void RenderLoopCallback(void* arg)
{
static_cast<MyView*>(arg)->Render();
}
EMSCRIPTEN_KEEPALIVE
void MyView::StartRenderingLoop()
{
emscripten_set_main_loop_arg(&RenderLoopCallback, this, -1, 1);
}
这是我一直在做的事情:
void do_frame(void* void_fn_ptr) {
auto* fn_ptr = reinterpret_cast<std::function<void()>*>(void_fn_ptr);
if (fn_ptr) {
auto& fn = *fn_ptr;
fn();
}
}
void window::loop(std::function<void()> fn) {
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_arg(do_frame, &fn, 0, 1);
#else
while (!should_close()) {
fn();
}
#endif
}
然后:
w.loop([&]() {
// render stuff...
});
我真的很难指示 emscripten_set_main_loop 执行渲染新帧的方法。我根本无法想出一个成功编译的 lambda,更不用说按预期运行了。
首先,我得到了 MyView
class,它应该作为 Javascript 的接口。这个想法是创建一个该类型的新对象,然后调用 StartRenderingLoop
这将启动渲染新帧的循环。这应该从 Javascript 开始,这就是为什么我在底部得到 Embind 定义的原因:
class MyView
{
public:
void StartRenderingLoop();
private:
std::unique_ptr<Renderer> _renderer;
void Render();
};
EMSCRIPTEN_KEEPALIVE
MyView::MyView()
{
_renderer = std::unique_ptr<Renderer>(new Renderer());
}
void MyView::Render()
{
_renderer->Render();
}
EMSCRIPTEN_KEEPALIVE
void MyView::StartRenderingLoop()
{
emscripten_set_main_loop(/* should invoke MyView::Render(), but how? */, -1, 1);
}
EMSCRIPTEN_BINDINGS(MyView)
{
class_<MyView>("MyView")
.function("startRenderingLoop", &MyView::StartRenderingLoop)
// everything else...
;
}
这是我尝试过的:
这甚至无法编译:
emscripten_set_main_loop(&MyView::Render(), -1, 1);
Emscripten 抛出以下错误:
note: candidate function not viable: no known conversion from 'void (MyView::*)()' to 'em_callback_func' (aka 'void (*)()') for 1st argument
不编译:
emscripten_set_main_loop([]() { _renderer->Render(); }, -1, 1);
因为它无法访问
this
指针,很公平:error: 'this' cannot be implicitly captured in this context
捕获
this
使 lambda 与预期不兼容并抛出类似于尝试 1 的错误:emscripten_set_main_loop([this]() { _renderer->Render(); }, -1, 1);
声明一个全局
std::function
对象:static std::function<void()> renderLoopFunction;
然后在
StartRenderingLoop
中做这样的事情:EMSCRIPTEN_KEEPALIVE void MyView::StartRenderingLoop() { renderLoopFunction = [=]() mutable { int test = 3; }; emscripten_set_main_loop(renderLoopFunction, -1, 1); }
与 this 等资源相反,它再次编译失败:
note: candidate function not viable: no known conversion from 'std::function<void ()>' to 'em_callback_func' (aka 'void (*)()') for 1st argument
我正处于这样一个阶段,如果有一个拥有三个免费愿望的仙女出现,我很乐意将其中一个用于解决这个谜团,只是为了让编译器停止告诉我我是一个多么无能的白痴.
该接口需要类型为 void (*)()
的普通旧 c 函数指针。
假设您只打算拥有一个 Render
对象...
class MyView
{
public:
void Render();
private:
std::unique_ptr<Renderer> _renderer;
};
// a global or otherwise known globally
auto view = MyView();
// &main_loop has the signature void (*)(), which is what you need
void main_loop()
{
view.Render();
}
int main()
{
emscripten_set_main_loop(&main_loop, -1, 1);
}
似乎为了利用 emscripten_set_main_loop_arg
我真的不得不退回到使用 C。因为我更喜欢尽可能地保持代码面向对象,所以我正在寻找替代方案。事实证明,该函数的第二个版本能够处理参数:emscripten_set_main_loop_arg
.
使用 emscripten_set_main_loop_arg
我可以将 StartRenderingLoop
方法保留为实例方法,只需将 this
传递给 Render
回调。修改后的代码如下:
void MyView::Render()
{
_renderer->Render();
}
void RenderLoopCallback(void* arg)
{
static_cast<MyView*>(arg)->Render();
}
EMSCRIPTEN_KEEPALIVE
void MyView::StartRenderingLoop()
{
emscripten_set_main_loop_arg(&RenderLoopCallback, this, -1, 1);
}
这是我一直在做的事情:
void do_frame(void* void_fn_ptr) {
auto* fn_ptr = reinterpret_cast<std::function<void()>*>(void_fn_ptr);
if (fn_ptr) {
auto& fn = *fn_ptr;
fn();
}
}
void window::loop(std::function<void()> fn) {
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_arg(do_frame, &fn, 0, 1);
#else
while (!should_close()) {
fn();
}
#endif
}
然后:
w.loop([&]() {
// render stuff...
});