我真的很努力指示emscripten_set_main_loop执行渲染新框架的方法。我根本无法提出可以成功编译的lambda,更不用说按预期运行了。
首先,我得到了MyView
类,该类应该用作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...
;
}
这是我尝试过的:
1)
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
2)
emscripten_set_main_loop([]() { _renderer->Render(); }, -1, 1);
由于无法访问this
指针而无法编译,这很公平:
error: 'this' cannot be implicitly captured in this context
3)
emscripten_set_main_loop([this]() { _renderer->Render(); }, -1, 1);
捕获this
会使lambda与预期值不兼容,并引发类似于尝试1)的错误。
4)
声明全局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
我正处于一个阶段,如果一个有三个自由愿望的仙女出现,我很乐意将其中一个投资于解决这个谜团,只是让编译器停止告诉我我是一个不称职的白痴。 / p>
答案 0 :(得分:1)
该接口需要类型为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);
}
答案 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);
}
答案 2 :(得分:0)
这是我一直在做的事情:
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...
});