]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_replay_window.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_replay_window.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_replay_window.cpp
27 #include "vogl_replay_window.h"
28
29 vogl_replay_window::vogl_replay_window()
30     : m_dpy(NULL),
31       m_win((Window)NULL),
32       m_width(0),
33       m_height(0),
34       m_pFB_configs(NULL),
35       m_num_fb_configs(0)
36 {
37     VOGL_FUNC_TRACER
38 }
39
40 vogl_replay_window::~vogl_replay_window()
41 {
42     VOGL_FUNC_TRACER
43
44     close();
45 }
46
47 bool vogl_replay_window::open(int width, int height)
48 {
49     VOGL_FUNC_TRACER
50
51     close();
52
53     if (!check_glx_version())
54         return false;
55
56     // TODO: These attribs (especially the sizes) should be passed in by the caller!
57     static int fbAttribs[] =
58         {
59             GLX_RENDER_TYPE, GLX_RGBA_BIT,
60             GLX_X_RENDERABLE, True,
61             GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
62             GLX_DOUBLEBUFFER, True,
63             GLX_RED_SIZE, 8,
64             GLX_BLUE_SIZE, 8,
65             GLX_GREEN_SIZE, 8,
66             GLX_ALPHA_SIZE, 8,
67             GLX_DEPTH_SIZE, 24,
68             GLX_STENCIL_SIZE, 8,
69             0
70         };
71
72     // Tell X we are going to use the display
73     m_dpy = XOpenDisplay(NULL);
74     if (!m_dpy)
75     {
76         console::error("%s: XOpenDisplay() failed!\n", VOGL_METHOD_NAME);
77         return false;
78     }
79
80     // Get a new fb config that meets our attrib requirements
81
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]);
84
85     // Now create an X window
86     XSetWindowAttributes winAttribs;
87     winAttribs.event_mask = ExposureMask | VisibilityChangeMask |
88                             KeyPressMask | PointerMotionMask |
89                             StructureNotifyMask;
90
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;
97
98     m_win = XCreateWindow(m_dpy, DefaultRootWindow(m_dpy), 20, 20,
99                           width, height, 0,
100                           pVisual_info->depth, InputOutput,
101                           pVisual_info->visual, winmask, &winAttribs);
102
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);
106
107     XSizeHints sh;
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)
110     sh.y = 0;
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);
115
116     XResizeWindow(m_dpy, m_win, width, height);
117
118     XMapWindow(m_dpy, m_win);
119
120     //glXWaitX();
121
122     m_width = width;
123     m_height = height;
124
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);
128
129     return true;
130 }
131
132 void vogl_replay_window::set_title(const char *pTitle)
133 {
134     VOGL_FUNC_TRACER
135
136     if (m_win)
137     {
138         XStoreName(m_dpy, m_win, pTitle);
139     }
140 }
141
142 bool vogl_replay_window::resize(int new_width, int new_height)
143 {
144     VOGL_FUNC_TRACER
145
146     if (!is_opened())
147         return open(new_width, new_height);
148
149     if ((new_width == m_width) && (new_height == m_height))
150         return true;
151
152     XSizeHints sh;
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);
159
160     int status = XResizeWindow(m_dpy, m_win, new_width, new_height);
161     VOGL_ASSERT(status == True);
162     VOGL_NOTE_UNUSED(status);
163
164     m_width = new_width;
165     m_height = new_height;
166
167     //glXWaitX();
168
169     return true;
170 }
171
172 void vogl_replay_window::clear_window()
173 {
174     VOGL_FUNC_TRACER
175
176     if (!m_dpy)
177         return;
178
179     XFillRectangle(m_dpy, m_win, DefaultGC(m_dpy, DefaultScreen(m_dpy)), 0, 0, m_width, m_height);
180 }
181
182 void vogl_replay_window::close()
183 {
184     VOGL_FUNC_TRACER
185
186     if (m_win)
187     {
188         XDestroyWindow(m_dpy, m_win);
189         m_win = (Window)NULL;
190     }
191
192     if (m_dpy)
193     {
194         XCloseDisplay(m_dpy);
195         m_dpy = NULL;
196     }
197
198     m_width = 0;
199     m_height = 0;
200 }
201
202 void vogl_replay_window::update_dimensions()
203 {
204     VOGL_FUNC_TRACER
205
206     //XWindowAttributes winData;
207     //XGetWindowAttributes(m_dpy, m_win, &winData);
208
209     //m_width = winData.width;
210     //m_height = winData.height;
211     uint w, h;
212     get_actual_dimensions(w, h);
213     m_width = w;
214     m_height = h;
215 }
216
217 bool vogl_replay_window::get_actual_dimensions(uint &width, uint &height) const
218 {
219     VOGL_FUNC_TRACER
220
221     Window root;
222     int x, y;
223     unsigned int border_width, depth;
224     return (XGetGeometry(m_dpy, m_win, &root, &x, &y, &width, &height, &border_width, &depth) != False);
225 }
226
227 bool vogl_replay_window::check_glx_version()
228 {
229     VOGL_FUNC_TRACER
230
231     GLint nMajorVer = 0;
232     VOGL_NOTE_UNUSED(nMajorVer);
233     GLint nMinorVer = 0;
234     VOGL_NOTE_UNUSED(nMinorVer);
235
236     if ((!GL_ENTRYPOINT(glXQueryVersion)) || (!GL_ENTRYPOINT(glXChooseFBConfig)) || (!GL_ENTRYPOINT(glXGetVisualFromFBConfig)))
237     {
238         vogl_debug_printf("Failed checking GLX version!\n");
239         return false;
240     }
241
242 #if 0
243         // This always returns 0, don't know why yet.
244         ACTUAL_GL_ENTRYPOINT(glXQueryVersion)(m_dpy, &nMajorVer, &nMinorVer);
245
246         vogl_debug_printf("Supported GLX version - %d.%d\n", nMajorVer, nMinorVer);
247
248         if (nMajorVer == 1 && nMinorVer < 2)
249         {
250                 vogl_error_printf("GLX 1.2 or greater is necessary\n");
251                 XCloseDisplay(m_dpy);
252                 return false;
253         }
254 #endif
255
256     return true;
257 }