(译)SimpleGLXWindow类

来源:互联网 发布:c语言初学者看什么书 编辑:程序博客网 时间:2024/06/08 03:26

介绍

在OpenGL游戏编程 - 第二版发布之后,很明显,最后一章中使用的SimpleGLXWindow类没有记载在书中!所以,对于那些喜欢快速开始的Linux用户来说,下面就是了!

类结构

SimpleGLXWindow的类结构与Win32版本非常相似。像Win32版本一样,它继承了BOGLGPWindow基类,因此实现了相同的虚拟方法。这里是类定义的参考:

class SimpleGLXWindow : public BOGLGPWindow{public:    SimpleGLXWindow(); //default constructor    virtual ~SimpleGLXWindow();    bool create(int width, int height, int bpp, bool fullscreen);    void destroy();    void processEvents();    void attachExample(Example* example);    bool isRunning(); //Is the window running?    void swapBuffers() { glXSwapBuffers(m_display, m_XWindow); }    float getElapsedSeconds();    KeyboardInterface* getKeyboard() const { return m_keyboard; }    MouseInterface* getMouse() const { return m_mouse; }private:    Example* m_example; //A link to the example program    bool m_isRunning; //Is the window still running?    Example* getAttachedExample() { return m_example; }    unsigned int m_lastTime;    Display* m_display;    Window m_XWindow;    GLXContext m_glContext;    XF86VidModeModeInfo m_XF86DeskMode;    XSetWindowAttributes m_XSetAttr;    int m_screenID;    bool m_isFullscreen;    unsigned int m_width;    unsigned int m_height;    unsigned int m_bpp;    bool m_GL3Supported;    KeyboardInterface* m_keyboard;    MouseInterface* m_mouse;};

窗口创建

窗口类最重要最复杂的部分是创建OpenGL窗口的代码。我们要做的第一件事就是使用XOpenDisplay获取默认显示的句柄,通过传递一个零(或NULL),这将获取DISPLAY环境变量中设置的任何显示(通常是用来查看桌面的那个) !)。

m_display = XOpenDisplay(0);  //Open default displayif (m_display == NULL){    std::cerr << "Could not open the display" << std::endl;    return false;}

所以,我们已经抓住了默认显示,如果有错误,我们已经记录了它,并返回false以指示窗口创建失败。接下来,我们得到一个标识显示器默认屏幕的句柄:

m_screenID = DefaultScreen(m_display); //Get the default screen id ```现在,我们列出可用的显示模式,看看是否符合我们的要求。如果不是的话,我们会退出一个错误:

XF86VidModeModeInfo **modes;
if (!XF86VidModeGetAllModeLines(m_display, m_screenID, &modeNum, &modes))
{
std::cerr << “Could not query the video modes” << std::endl;
return false;
}

int bestMode = -1;
for (int i = 0; i < modeNum; i++)
{
if ((modes[i]->hdisplay == width) &&
(modes[i]->vdisplay == height))
{
bestMode = i;
}
}

if (bestMode == -1)
{
std::cerr << “Could not find a suitable graphics mode” << std::endl;
return false;
}
“`
在我们存储了最佳匹配的显示模式之后,我们要求一个具有16位深度缓冲区的双缓冲窗口:

int doubleBufferedAttribList [] = {    GLX_RGBA, GLX_DOUBLEBUFFER,    GLX_RED_SIZE, 4,    GLX_GREEN_SIZE, 4,    GLX_BLUE_SIZE, 4,    GLX_DEPTH_SIZE, 16,    None};XVisualInfo* vi = NULL;//Attempt to create a double buffered windowvi = glXChooseVisual(m_display, m_screenID, doubleBufferedAttribList);if (vi == NULL){    std::cerr << "Could not create a double buffered window" << std::endl;    return false;} ```下一步是创建一个OpenGL 2.1上下文,所以我们可以请求一个GL3。这些是我们必须采取的与Windows相同的步骤:

//Create a GL 2.1 context
GLXContext gl2Context = glXCreateContext(m_display, vi, 0, GL_TRUE);

if (gl2Context == NULL)
{
std::cerr << “Could not create a GL 2.1 context, please check your graphics drivers” << std::endl;
return false;
}

//Get a pointer to the GL 3.0 context creation
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((GLubyte*)”glXCreateContextAttribsARB”);

if (glXCreateContextAttribs == NULL)
{
std::cerr << “OpenGL 3.0 is not supported, falling back to 2.1” << std::endl;
m_glContext = gl2Context;
m_GL3Supported = false;
}
else
{
//Create a GL 3.0 context

int attribs[] = {    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,//we want a 3.0 context    GLX_CONTEXT_MINOR_VERSION_ARB, 0,    0 //zero indicates the end of the array};m_glContext = glXCreateContextAttribs(m_display, framebufferConfig, 0, true, &attribs[0]);glXDestroyContext(m_display, gl2Context); //We can destroy the GL 2.0 context once the 3.0 one has bene createdm_GL3Supported = true;

}
“`
如果不支持OpenGL 3.0,我们设置一个标志,以便我们可以使用后备2.1着色器。

现在我们有足够的信息来实际创建窗口。记得我们存储了我们能找到的最好的显示模式吗?在设置了一些窗口配置设置后,我们使用下面的代码:

Colormap cmap = XCreateColormap(m_display, RootWindow(m_display, vi->screen),vi->visual, AllocNone);m_XSetAttr.colormap = cmap;m_XSetAttr.border_pixel = 0;m_XSetAttr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |                            StructureNotifyMask;m_XSetAttr.override_redirect = False;unsigned long windowAttributes = CWBorderPixel | CWColormap | CWEventMask;if (fullscreen){    windowAttributes = CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;    XF86VidModeSwitchToMode(m_display, m_screenID, modes[bestMode]);    XF86VidModeSetViewPort(m_display, m_screenID, 0, 0);    m_XSetAttr.override_redirect = True;}m_XWindow = XCreateWindow(m_display, RootWindow(m_display, vi->screen),                              0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,                              CWBorderPixel | CWColormap | CWEventMask, &m_XSetAttr); ```最后,我们设置窗口标题,如果我们是全屏,我们抓住光标:

if (fullscreen)
{
XWarpPointer(m_display, None, m_XWindow, 0, 0, 0, 0, 0, 0);
XMapRaised(m_display, m_XWindow);
XGrabKeyboard(m_display, m_XWindow, True, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabPointer(m_display, m_XWindow, True, ButtonPressMask,
GrabModeAsync, GrabModeAsync, m_XWindow, None, CurrentTime);

m_isFullscreen = true;

}
else
{
Atom wmDelete = XInternAtom(m_display, “WM_DELETE_WINDOW”, True);
XSetWMProtocols(m_display, m_XWindow, &wmDelete, 1);
XSetStandardProperties(m_display, m_XWindow, title.c_str(), None, NULL, NULL, 0, NULL);
XMapRaised(m_display, m_XWindow);
}

XFree(modes);

上面的最后一行释放了我们之前搜索的显示模式的内存。破坏窗口这很简单,代码如下:

void SimpleGLXWindow::destroy()
{
m_mouse->showCursor(true);
if (m_glContext)
{
glXMakeCurrent(m_display, None, NULL);
glXDestroyContext(m_display, m_glContext);
m_glContext = NULL;
}

if (m_isFullscreen){    XF86VidModeSwitchToMode(m_display, m_screenID, &m_XF86DeskMode);    XF86VidModeSetViewPort(m_display, m_screenID, 0, 0);}XCloseDisplay(m_display);

}
“`
基本上,我们确保光标是可见的,然后我们销毁OpenGL上下文,最后在完成时切换显示模式。我们在显示器上释放我们的手柄,窗户被完全破坏。

如果您还有其他问题,无论是关于本文还是本书,或者在论坛上告诉我,或者在Twitters上戳我。

原创粉丝点击