1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_replay_window.cpp
27 #include "vogl_replay_window.h"
29 vogl_replay_window::vogl_replay_window()
40 vogl_replay_window::~vogl_replay_window()
47 bool vogl_replay_window::open(int width, int height)
53 if (!check_glx_version())
56 // TODO: These attribs (especially the sizes) should be passed in by the caller!
57 static int fbAttribs[] =
59 GLX_RENDER_TYPE, GLX_RGBA_BIT,
60 GLX_X_RENDERABLE, True,
61 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
62 GLX_DOUBLEBUFFER, True,
72 // Tell X we are going to use the display
73 m_dpy = XOpenDisplay(NULL);
76 console::error("%s: XOpenDisplay() failed!\n", VOGL_METHOD_NAME);
80 // Get a new fb config that meets our attrib requirements
82 m_pFB_configs = GL_ENTRYPOINT(glXChooseFBConfig)(m_dpy, DefaultScreen(m_dpy), fbAttribs, &m_num_fb_configs);
83 XVisualInfo *pVisual_info = GL_ENTRYPOINT(glXGetVisualFromFBConfig)(m_dpy, m_pFB_configs[0]);
85 // Now create an X window
86 XSetWindowAttributes winAttribs;
87 winAttribs.event_mask = ExposureMask | VisibilityChangeMask |
88 KeyPressMask | PointerMotionMask |
91 winAttribs.border_pixel = 0;
92 winAttribs.bit_gravity = StaticGravity;
93 winAttribs.colormap = XCreateColormap(m_dpy,
94 RootWindow(m_dpy, pVisual_info->screen),
95 pVisual_info->visual, AllocNone);
96 GLint winmask = CWBorderPixel | CWBitGravity | CWEventMask | CWColormap;
98 m_win = XCreateWindow(m_dpy, DefaultRootWindow(m_dpy), 20, 20,
100 pVisual_info->depth, InputOutput,
101 pVisual_info->visual, winmask, &winAttribs);
103 const char *pWindow_name = (sizeof(void *) == sizeof(uint32)) ? "voglreplay 32-bit" : "voglreplay 64-bit";
104 XStoreName(m_dpy, m_win, pWindow_name);
105 XSetIconName(m_dpy, m_win, pWindow_name);
108 utils::zero_object(sh);
109 sh.x = 0; // slam position up so when/if we resize the window glReadPixels still works as expected (this may be a bug in the NV driver, I dunno yet)
111 sh.width = sh.min_width = sh.max_width = sh.base_width = width;
112 sh.height = sh.min_height = sh.max_height = sh.base_height = height;
113 sh.flags = PSize | PMinSize | PMaxSize | PBaseSize | PPosition;
114 XSetWMNormalHints(m_dpy, m_win, &sh);
116 XResizeWindow(m_dpy, m_win, width, height);
118 XMapWindow(m_dpy, m_win);
125 uint actual_width = 0, actual_height = 0;
126 vogl_replay_window::get_actual_dimensions(actual_width, actual_height);
127 vogl_debug_printf("%s: Created window, requested dimensions %ux%u, actual dimensions %ux%u\n", VOGL_METHOD_NAME, m_width, m_height, actual_width, actual_height);
132 void vogl_replay_window::set_title(const char *pTitle)
138 XStoreName(m_dpy, m_win, pTitle);
142 bool vogl_replay_window::resize(int new_width, int new_height)
147 return open(new_width, new_height);
149 if ((new_width == m_width) && (new_height == m_height))
153 utils::zero_object(sh);
154 sh.width = sh.min_width = sh.max_width = sh.base_width = new_width;
155 sh.height = sh.min_height = sh.max_height = sh.base_height = new_height;
156 sh.flags = PSize | PMinSize | PMaxSize | PBaseSize;
157 XSetWMNormalHints(m_dpy, m_win, &sh);
158 //XMapWindow(dpy, win);
160 int status = XResizeWindow(m_dpy, m_win, new_width, new_height);
161 VOGL_ASSERT(status == True);
162 VOGL_NOTE_UNUSED(status);
165 m_height = new_height;
172 void vogl_replay_window::clear_window()
179 XFillRectangle(m_dpy, m_win, DefaultGC(m_dpy, DefaultScreen(m_dpy)), 0, 0, m_width, m_height);
182 void vogl_replay_window::close()
188 XDestroyWindow(m_dpy, m_win);
189 m_win = (Window)NULL;
194 XCloseDisplay(m_dpy);
202 void vogl_replay_window::update_dimensions()
206 //XWindowAttributes winData;
207 //XGetWindowAttributes(m_dpy, m_win, &winData);
209 //m_width = winData.width;
210 //m_height = winData.height;
212 get_actual_dimensions(w, h);
217 bool vogl_replay_window::get_actual_dimensions(uint &width, uint &height) const
223 unsigned int border_width, depth;
224 return (XGetGeometry(m_dpy, m_win, &root, &x, &y, &width, &height, &border_width, &depth) != False);
227 bool vogl_replay_window::check_glx_version()
232 VOGL_NOTE_UNUSED(nMajorVer);
234 VOGL_NOTE_UNUSED(nMinorVer);
236 if ((!GL_ENTRYPOINT(glXQueryVersion)) || (!GL_ENTRYPOINT(glXChooseFBConfig)) || (!GL_ENTRYPOINT(glXGetVisualFromFBConfig)))
238 vogl_debug_printf("Failed checking GLX version!\n");
243 // This always returns 0, don't know why yet.
244 ACTUAL_GL_ENTRYPOINT(glXQueryVersion)(m_dpy, &nMajorVer, &nMinorVer);
246 vogl_debug_printf("Supported GLX version - %d.%d\n", nMajorVer, nMinorVer);
248 if (nMajorVer == 1 && nMinorVer < 2)
250 vogl_error_printf("GLX 1.2 or greater is necessary\n");
251 XCloseDisplay(m_dpy);