sci*_*pie 13 windows cocoa message-loop
在尝试将我的游戏引擎移植到mac时,我偶然发现了一个基本(但很大)的问题.在Windows上,我的主要代码看起来像这样(非常简化):
PeekMessage(...) // check for windows messages
switch (msg.message)
{
case WM_QUIT: ...;
case WM_LBUTTONDOWN: ...;
...
}
TranslateMessage(&msg);
DispatchMessage (&msg);
for (std::vector<CMyBackgroundThread*>::iterator it = mythreads.begin(); it != mythreads.end(); ++it)
{
(*it)->processEvents();
}
... do other useful stuff like look if the window has resized and other stuff...
drawFrame(); // draw a frame using opengl
SwapBuffers(hDC); // swap backbuffer/frontbuffer
if (g_sleep > 0) Sleep(g_sleep);
Run Code Online (Sandbox Code Playgroud)
我已经读过这不是mac方式.mac方式是检查某种事件,例如屏幕的v-sync以呈现新帧.但正如你所看到的,我想做的不仅仅是渲染,我希望其他线程能够工作.有些线程需要比每1/60秒更快地调用一次.(顺便说一句,我的线程基础结构是:线程将事件放入同步队列中,主线程调用processEvents来处理主线程内该同步队列中的项目.这用于网络内容,图像加载/处理内容,perlin噪声一代等...等...)
我希望能够以类似的方式做到这一点,但很少有关于此的信息.我不介意将渲染放在v-sync事件上(我也将在Windows上实现),但我希望对其余代码有更多响应.
以这种方式看待它:我很乐意能够处理其余部分,而GPU正在做任何事情,我不想等待v-sync然后开始做已经处理过的东西才开始将内容发送到GPU.你明白我的意思吗?
如果我需要从完全不同的角度来看待这个问题,请告诉我.
如果我需要阅读书籍/指南/教程/任何内容,请告诉我要阅读的内容!
我不是可可开发人员,我不是对象程序员,我的游戏引擎完全是用C++编写的,但我知道我的方式足以让xcode出现并显示我在该窗口内绘制的内容.它只是不像我的Windows版本更新,因为我不知道如何正确.
更新:我甚至认为我需要某种循环,即使我想在垂直回扫上同步.MacOSX文档中的OpenGL编程显示,这是通过设置SwapInterval来完成的.因此,如果我理解正确,在Mac上实时渲染时,我总是需要某种循环,使用swapInterval设置来降低功耗.这是真的?
sci*_*pie 15
虽然我不能成为世界上唯一一个试图实现这一目标的人,但似乎没有人愿意回答这个问题(不是指向你们的堆栈流,而是指向知道它如何工作的mac开发人员).这就是为什么我想要改变这种典型行为并帮助那些寻找同样事物的人.换句话说:我找到了解决方案!我仍然需要进一步改进这段代码,但基本上就是这样!
1 /当你需要一个真正的循环时,就像在windows中一样,你需要自己处理它.所以,让cocoa构建你的标准代码,但是请使用main.m(如果需要,将其更改为.mm for c ++,这是因为我使用了c ++)并删除了唯一的代码行.您不会允许cocoa为您设置应用程序/窗口/视图.
2/Cocoa通常会为您创建一个AutoreleasePool.它可以帮助您进行内存管理.现在,这将不再发生,因此您需要初始化它.您在main函数中的第一行将是:
[[NSAutoreleasePool alloc] init];
Run Code Online (Sandbox Code Playgroud)
3 /现在您需要设置应用程序委托.XCode向导已经为您设置了AppDelegate类,因此您只需要使用该类.此外,向导已经设置了主菜单,可能还称为MainMenu.xib.开始时可以使用默认值.确保在#import <Cocoa/Cocoa.h>行之后#import"YourAppDelegate.h".然后在main函数中添加以下代码:
[NSApplication sharedApplication];
[NSApp setDelegate:[[[YourAppDelegate alloc] init] autorelease]];
[NSBundle loadNibNamed:@"MainMenu" owner:[NSApp delegate]];
[NSApp finishLaunching];
Run Code Online (Sandbox Code Playgroud)
4/Mac OS现在将知道应用程序的内容,将为其添加主菜单.无论如何,运行它不会做太多,因为还没有窗口.让我们创建它:
[Window setDelegate:[NSApp delegate]];
[Window setAcceptsMouseMovedEvents:TRUE];
[Window setIsVisible:TRUE];
[Window makeKeyAndOrderFront:nil];
[Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask];
Run Code Online (Sandbox Code Playgroud)
为了展示你在这里可以做什么,我添加了一个标题栏并启用了关闭按钮.你可以做更多,但我还需要先学习.
5 /现在,如果你运行它,你可能会很幸运,看到一个微秒的窗口,但你可能看不到任何东西,因为...程序还没有循环.让我们添加一个循环并监听传入的事件:
bool quit = false;
while (!quit)
{
NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES];
switch([(NSEvent *)event type])
{
case NSKeyDown:
quit = true;
break;
default:
[NSApp sendEvent:event];
break;
}
[event release];
}
Run Code Online (Sandbox Code Playgroud)
如果你运行它,你会看到窗口出现,只有按一个键才能看到它.按键时,应用程序将立即退出.
就是这个!但要注意......查看活动监视器.您将看到您的应用程序使用100%CPU.为什么?因为循环不会使CPU处于睡眠模式.这取决于你现在.你可以轻松自己做一个睡眠(10000); 在此期间.这将做很多事,但不是最佳的.我可能会使用opengl的vertical-sync来确保CPU没有被过度使用,我也会等待来自我的线程的事件.也许我甚至会自己查看过去的时间并做一个计算的睡眠来制作每帧的总时间,以便我有一个不错的帧速率.
有关Opengl的帮助:
1 /将cocoa.opengl框架添加到项目中.
2 /在[Window ...]之前放:
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowattribs];
NSOpenGLContext *OGLContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:NULL];
[format release];
Run Code Online (Sandbox Code Playgroud)
3 /在[Window setDelegate:...]之后放:
[OGLContext setView:[Window contentView]];
Run Code Online (Sandbox Code Playgroud)
4 /窗口处理后的某处,放:
[OGLContext makeCurrentContext];
Run Code Online (Sandbox Code Playgroud)
5/[事件发布]之后,放:
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
[OGLContext flushBuffer];
Run Code Online (Sandbox Code Playgroud)
这将在我的mac book pro 2011上以3300的帧率清除你的窗口全红色.
同样,此代码不完整.当您单击关闭按钮并重新打开它时,它将不再起作用.我可能需要挂钩事件,我还不知道它们(经过进一步的研究,这些事情可以在AppDelegate中完成).此外,还有很多其他事情要做/考虑.但这是一个开始.请随时纠正我/填写/ ...
如果我完全正确,我可能会为此设置一个教程网页,如果没有人打败我.
我希望这能帮助你们!
归档时间: |
|
查看次数: |
3571 次 |
最近记录: |