gosu 0.7.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING.txt +29 -0
- data/Gosu/Async.hpp +48 -0
- data/Gosu/Audio.hpp +145 -0
- data/Gosu/AutoLink.hpp +16 -0
- data/Gosu/Bitmap.hpp +85 -0
- data/Gosu/ButtonsMac.hpp +114 -0
- data/Gosu/ButtonsWin.hpp +111 -0
- data/Gosu/ButtonsX.hpp +115 -0
- data/Gosu/Color.hpp +172 -0
- data/Gosu/Directories.hpp +36 -0
- data/Gosu/Font.hpp +59 -0
- data/Gosu/Fwd.hpp +31 -0
- data/Gosu/Gosu.hpp +26 -0
- data/Gosu/Graphics.hpp +86 -0
- data/Gosu/GraphicsBase.hpp +45 -0
- data/Gosu/IO.hpp +255 -0
- data/Gosu/Image.hpp +148 -0
- data/Gosu/ImageData.hpp +45 -0
- data/Gosu/Input.hpp +116 -0
- data/Gosu/Math.hpp +95 -0
- data/Gosu/Platform.hpp +61 -0
- data/Gosu/RotFlip.hpp +116 -0
- data/Gosu/Sockets.hpp +129 -0
- data/Gosu/Text.hpp +47 -0
- data/Gosu/TextInput.hpp +57 -0
- data/Gosu/Timing.hpp +16 -0
- data/Gosu/Utility.hpp +24 -0
- data/Gosu/WinUtility.hpp +76 -0
- data/Gosu/Window.hpp +84 -0
- data/GosuImpl/Async.cpp +37 -0
- data/GosuImpl/AudioFmod.cpp +417 -0
- data/GosuImpl/AudioSDL.cpp +255 -0
- data/GosuImpl/DirectoriesMac.mm +38 -0
- data/GosuImpl/DirectoriesUnix.cpp +48 -0
- data/GosuImpl/DirectoriesWin.cpp +42 -0
- data/GosuImpl/FileUnix.cpp +100 -0
- data/GosuImpl/FileWin.cpp +83 -0
- data/GosuImpl/Graphics/Bitmap.cpp +116 -0
- data/GosuImpl/Graphics/BitmapBMP.cpp +232 -0
- data/GosuImpl/Graphics/BitmapColorKey.cpp +39 -0
- data/GosuImpl/Graphics/BitmapPNG.cpp +276 -0
- data/GosuImpl/Graphics/BitmapUtils.cpp +67 -0
- data/GosuImpl/Graphics/BlockAllocator.cpp +127 -0
- data/GosuImpl/Graphics/BlockAllocator.hpp +34 -0
- data/GosuImpl/Graphics/Color.cpp +126 -0
- data/GosuImpl/Graphics/Common.hpp +21 -0
- data/GosuImpl/Graphics/DrawOp.hpp +154 -0
- data/GosuImpl/Graphics/Font.cpp +110 -0
- data/GosuImpl/Graphics/Graphics.cpp +295 -0
- data/GosuImpl/Graphics/Image.cpp +159 -0
- data/GosuImpl/Graphics/LargeImageData.cpp +115 -0
- data/GosuImpl/Graphics/LargeImageData.hpp +37 -0
- data/GosuImpl/Graphics/RotFlip.cpp +184 -0
- data/GosuImpl/Graphics/TexChunk.cpp +77 -0
- data/GosuImpl/Graphics/TexChunk.hpp +40 -0
- data/GosuImpl/Graphics/Text.cpp +223 -0
- data/GosuImpl/Graphics/TextMac.cpp +242 -0
- data/GosuImpl/Graphics/TextPangoFT.cpp +186 -0
- data/GosuImpl/Graphics/TextWin.cpp +172 -0
- data/GosuImpl/Graphics/Texture.cpp +104 -0
- data/GosuImpl/Graphics/Texture.hpp +34 -0
- data/GosuImpl/IO.cpp +48 -0
- data/GosuImpl/InputMac.mm +677 -0
- data/GosuImpl/InputWin.cpp +444 -0
- data/GosuImpl/InputX.cpp +158 -0
- data/GosuImpl/MacUtility.hpp +48 -0
- data/GosuImpl/Math.cpp +49 -0
- data/GosuImpl/RubyGosu.swg +474 -0
- data/GosuImpl/RubyGosuStub.mm +17 -0
- data/GosuImpl/RubyGosu_DllMain.cxx +30 -0
- data/GosuImpl/RubyGosu_wrap.cxx +8521 -0
- data/GosuImpl/RubyGosu_wrap.h +31 -0
- data/GosuImpl/Sockets/CommSocket.cpp +304 -0
- data/GosuImpl/Sockets/ListenerSocket.cpp +60 -0
- data/GosuImpl/Sockets/MessageSocket.cpp +136 -0
- data/GosuImpl/Sockets/Socket.cpp +145 -0
- data/GosuImpl/Sockets/Sockets.hpp +66 -0
- data/GosuImpl/TextInputMac.mm +207 -0
- data/GosuImpl/TextInputWin.cpp +197 -0
- data/GosuImpl/TextInputX.cpp +201 -0
- data/GosuImpl/TextTTFWin.cpp +247 -0
- data/GosuImpl/TimingUnix.cpp +17 -0
- data/GosuImpl/TimingWin.cpp +28 -0
- data/GosuImpl/Utility.cpp +140 -0
- data/GosuImpl/WinMain.cpp +69 -0
- data/GosuImpl/WinUtility.cpp +137 -0
- data/GosuImpl/WindowMac.mm +466 -0
- data/GosuImpl/WindowWin.cpp +447 -0
- data/GosuImpl/WindowX.cpp +392 -0
- data/GosuImpl/X11vroot.h +118 -0
- data/README.txt +13 -0
- data/Rakefile +178 -0
- data/examples/ChipmunkIntegration.rb +275 -0
- data/examples/CptnRuby.rb +231 -0
- data/examples/MoreChipmunkAndRMagick.rb +155 -0
- data/examples/OpenGLIntegration.rb +232 -0
- data/examples/RMagickIntegration.rb +449 -0
- data/examples/TextInput.cpp +170 -0
- data/examples/TextInput.rb +139 -0
- data/examples/Tutorial.cpp +215 -0
- data/examples/Tutorial.rb +137 -0
- data/examples/media/Beep.wav +0 -0
- data/examples/media/CptnRuby Gem.png +0 -0
- data/examples/media/CptnRuby Map.txt +25 -0
- data/examples/media/CptnRuby Tileset.png +0 -0
- data/examples/media/CptnRuby.png +0 -0
- data/examples/media/Cursor.png +0 -0
- data/examples/media/Earth.png +0 -0
- data/examples/media/Explosion.wav +0 -0
- data/examples/media/LargeStar.png +0 -0
- data/examples/media/Sky.jpg +0 -0
- data/examples/media/Smoke.png +0 -0
- data/examples/media/Soldier.png +0 -0
- data/examples/media/Space.png +0 -0
- data/examples/media/Star.png +0 -0
- data/examples/media/Starfighter.bmp +0 -0
- data/linux/Makefile.in +98 -0
- data/linux/configure +5658 -0
- data/linux/configure.ac +126 -0
- data/linux/extconf.rb +11 -0
- data/mac/English.lproj/InfoPlist.strings +0 -0
- data/mac/Gosu-Info.plist +26 -0
- data/mac/Gosu.xcodeproj/project.pbxproj +1194 -0
- data/mac/RubyGosu Template-Info.plist +26 -0
- data/mac/libboost_thread_1_34_1_universal.a +0 -0
- data/mac/libboost_thread_d_1_34_1_universal.a +0 -0
- data/mac/libfmod_universal.a +0 -0
- data/mac/libpng_universal.a +0 -0
- data/mac/libz_universal.a +0 -0
- data/reference/Async_8hpp-source.html +70 -0
- data/reference/Audio_8hpp-source.html +114 -0
- data/reference/Audio_8hpp.html +50 -0
- data/reference/AutoLink_8hpp-source.html +38 -0
- data/reference/AutoLink_8hpp.html +34 -0
- data/reference/Bitmap_8hpp-source.html +85 -0
- data/reference/Bitmap_8hpp.html +58 -0
- data/reference/ButtonsMac_8hpp-source.html +133 -0
- data/reference/ButtonsWin_8hpp-source.html +133 -0
- data/reference/ButtonsX_8hpp-source.html +134 -0
- data/reference/Color_8hpp-source.html +169 -0
- data/reference/Color_8hpp.html +85 -0
- data/reference/Directories_8hpp-source.html +42 -0
- data/reference/Directories_8hpp.html +46 -0
- data/reference/Font_8hpp-source.html +65 -0
- data/reference/Font_8hpp.html +41 -0
- data/reference/Fwd_8hpp-source.html +52 -0
- data/reference/Fwd_8hpp.html +37 -0
- data/reference/Gosu_8hpp-source.html +48 -0
- data/reference/Gosu_8hpp.html +34 -0
- data/reference/GraphicsBase_8hpp-source.html +57 -0
- data/reference/GraphicsBase_8hpp.html +56 -0
- data/reference/Graphics_8hpp-source.html +96 -0
- data/reference/Graphics_8hpp.html +53 -0
- data/reference/IO_8hpp-source.html +255 -0
- data/reference/IO_8hpp.html +74 -0
- data/reference/ImageData_8hpp-source.html +62 -0
- data/reference/ImageData_8hpp.html +43 -0
- data/reference/Image_8hpp-source.html +126 -0
- data/reference/Image_8hpp.html +48 -0
- data/reference/Input_8hpp-source.html +118 -0
- data/reference/Input_8hpp.html +50 -0
- data/reference/Math_8hpp-source.html +92 -0
- data/reference/Math_8hpp.html +74 -0
- data/reference/Platform_8hpp-source.html +83 -0
- data/reference/Platform_8hpp.html +73 -0
- data/reference/RotFlip_8hpp-source.html +138 -0
- data/reference/RotFlip_8hpp.html +77 -0
- data/reference/Sockets_8hpp-source.html +130 -0
- data/reference/Sockets_8hpp.html +66 -0
- data/reference/TextInput_8hpp-source.html +64 -0
- data/reference/TextInput_8hpp.html +41 -0
- data/reference/Text_8hpp-source.html +51 -0
- data/reference/Text_8hpp.html +46 -0
- data/reference/Timing_8hpp-source.html +36 -0
- data/reference/Timing_8hpp.html +42 -0
- data/reference/Utility_8hpp-source.html +44 -0
- data/reference/Utility_8hpp.html +48 -0
- data/reference/WinUtility_8hpp-source.html +79 -0
- data/reference/WinUtility_8hpp.html +64 -0
- data/reference/Window_8hpp-source.html +91 -0
- data/reference/Window_8hpp.html +41 -0
- data/reference/annotated.html +51 -0
- data/reference/classGosu_1_1Audio-members.html +34 -0
- data/reference/classGosu_1_1Audio.html +46 -0
- data/reference/classGosu_1_1Bitmap-members.html +44 -0
- data/reference/classGosu_1_1Bitmap.html +263 -0
- data/reference/classGosu_1_1Buffer-members.html +44 -0
- data/reference/classGosu_1_1Buffer.html +78 -0
- data/reference/classGosu_1_1Buffer.png +0 -0
- data/reference/classGosu_1_1Button-members.html +36 -0
- data/reference/classGosu_1_1Button.html +143 -0
- data/reference/classGosu_1_1Color-members.html +56 -0
- data/reference/classGosu_1_1Color.html +387 -0
- data/reference/classGosu_1_1File-members.html +41 -0
- data/reference/classGosu_1_1File.html +69 -0
- data/reference/classGosu_1_1File.png +0 -0
- data/reference/classGosu_1_1Font-members.html +39 -0
- data/reference/classGosu_1_1Font.html +309 -0
- data/reference/classGosu_1_1Graphics-members.html +50 -0
- data/reference/classGosu_1_1Graphics.html +234 -0
- data/reference/classGosu_1_1Image-members.html +45 -0
- data/reference/classGosu_1_1Image.html +518 -0
- data/reference/classGosu_1_1ImageData-members.html +37 -0
- data/reference/classGosu_1_1ImageData.html +60 -0
- data/reference/classGosu_1_1Input-members.html +44 -0
- data/reference/classGosu_1_1Input.html +223 -0
- data/reference/classGosu_1_1MessageSocket-members.html +40 -0
- data/reference/classGosu_1_1MessageSocket.html +233 -0
- data/reference/classGosu_1_1Resource-members.html +39 -0
- data/reference/classGosu_1_1Resource.html +116 -0
- data/reference/classGosu_1_1Resource.png +0 -0
- data/reference/classGosu_1_1Sample-members.html +37 -0
- data/reference/classGosu_1_1Sample.html +200 -0
- data/reference/classGosu_1_1SampleInstance-members.html +38 -0
- data/reference/classGosu_1_1SampleInstance.html +169 -0
- data/reference/classGosu_1_1Song-members.html +43 -0
- data/reference/classGosu_1_1Song.html +260 -0
- data/reference/classGosu_1_1TextInput-members.html +38 -0
- data/reference/classGosu_1_1TextInput.html +121 -0
- data/reference/classGosu_1_1Window-members.html +50 -0
- data/reference/classGosu_1_1Window.html +271 -0
- data/reference/doxyfile +233 -0
- data/reference/doxygen.css +433 -0
- data/reference/doxygen.png +0 -0
- data/reference/files.html +54 -0
- data/reference/functions.html +236 -0
- data/reference/functions_enum.html +45 -0
- data/reference/functions_func.html +227 -0
- data/reference/functions_vars.html +47 -0
- data/reference/hierarchy.html +53 -0
- data/reference/index.html +26 -0
- data/reference/namespaceGosu.html +2890 -0
- data/reference/namespaceGosu_1_1Colors.html +70 -0
- data/reference/namespaceGosu_1_1Win.html +275 -0
- data/reference/namespacemembers.html +216 -0
- data/reference/namespacemembers_enum.html +52 -0
- data/reference/namespacemembers_eval.html +54 -0
- data/reference/namespacemembers_func.html +185 -0
- data/reference/namespacemembers_type.html +46 -0
- data/reference/namespacemembers_vars.html +46 -0
- data/reference/namespaces.html +35 -0
- data/reference/tab_b.gif +0 -0
- data/reference/tab_l.gif +0 -0
- data/reference/tab_r.gif +0 -0
- data/reference/tabs.css +102 -0
- data/windows/Gosu.sln +29 -0
- data/windows/Gosu.vcproj +553 -0
- data/windows/RubyGosu.vcproj +138 -0
- metadata +305 -0
@@ -0,0 +1,447 @@
|
|
1
|
+
#include <Gosu/Window.hpp>
|
2
|
+
#include <Gosu/WinUtility.hpp>
|
3
|
+
#include <Gosu/Timing.hpp>
|
4
|
+
#include <Gosu/Graphics.hpp>
|
5
|
+
#include <Gosu/Audio.hpp>
|
6
|
+
#include <Gosu/Input.hpp>
|
7
|
+
#include <Gosu/TextInput.hpp>
|
8
|
+
#include <GosuImpl/Graphics/Common.hpp>
|
9
|
+
#include <boost/bind.hpp>
|
10
|
+
#include <cassert>
|
11
|
+
#include <stdexcept>
|
12
|
+
#include <vector>
|
13
|
+
|
14
|
+
// TODO: Put fullscreen logic in different file, track fullscreen state and
|
15
|
+
// enable dynamic toggling between fullscreen and window.
|
16
|
+
|
17
|
+
namespace Gosu
|
18
|
+
{
|
19
|
+
namespace
|
20
|
+
{
|
21
|
+
// Mode guessing experimentally adapted from GLFW library.
|
22
|
+
// http://glfw.sourceforge.net/
|
23
|
+
|
24
|
+
int findClosestVideoMode(int *w, int *h, int *bpp, int *refresh)
|
25
|
+
{
|
26
|
+
int mode, bestmode, match, bestmatch, rr, bestrr, success;
|
27
|
+
DEVMODE dm;
|
28
|
+
|
29
|
+
// Find best match
|
30
|
+
bestmatch = 0x7fffffff;
|
31
|
+
bestrr = 0x7fffffff;
|
32
|
+
mode = bestmode = 0;
|
33
|
+
do
|
34
|
+
{
|
35
|
+
dm.dmSize = sizeof(DEVMODE);
|
36
|
+
success = EnumDisplaySettings(NULL, mode, &dm);
|
37
|
+
if( success )
|
38
|
+
{
|
39
|
+
match = dm.dmBitsPerPel - *bpp;
|
40
|
+
if( match < 0 ) match = -match;
|
41
|
+
match = (match << 25) |
|
42
|
+
((dm.dmPelsWidth - *w) * (dm.dmPelsWidth - *w) +
|
43
|
+
(dm.dmPelsHeight - *h) * (dm.dmPelsHeight - *h));
|
44
|
+
if( match < bestmatch )
|
45
|
+
{
|
46
|
+
bestmatch = match;
|
47
|
+
bestmode = mode;
|
48
|
+
bestrr = (dm.dmDisplayFrequency - *refresh) *
|
49
|
+
(dm.dmDisplayFrequency - *refresh);
|
50
|
+
}
|
51
|
+
else if( match == bestmatch && *refresh > 0 )
|
52
|
+
{
|
53
|
+
rr = (dm.dmDisplayFrequency - *refresh) *
|
54
|
+
(dm.dmDisplayFrequency - *refresh);
|
55
|
+
if( rr < bestrr )
|
56
|
+
{
|
57
|
+
bestmatch = match;
|
58
|
+
bestmode = mode;
|
59
|
+
bestrr = rr;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
++mode;
|
64
|
+
}
|
65
|
+
while (success);
|
66
|
+
|
67
|
+
// Get the parameters for the best matching display mode
|
68
|
+
dm.dmSize = sizeof(DEVMODE);
|
69
|
+
EnumDisplaySettings( NULL, bestmode, &dm );
|
70
|
+
|
71
|
+
*w = dm.dmPelsWidth;
|
72
|
+
*h = dm.dmPelsHeight;
|
73
|
+
*bpp = dm.dmBitsPerPel;
|
74
|
+
*refresh = dm.dmDisplayFrequency;
|
75
|
+
|
76
|
+
return bestmode;
|
77
|
+
}
|
78
|
+
|
79
|
+
void setVideoMode(int mode)
|
80
|
+
{
|
81
|
+
// Get the parameters for the best matching display mode
|
82
|
+
DEVMODE dm;
|
83
|
+
dm.dmSize = sizeof(DEVMODE);
|
84
|
+
EnumDisplaySettings(NULL, mode, &dm);
|
85
|
+
|
86
|
+
// Set which fields we want to specify
|
87
|
+
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
|
88
|
+
|
89
|
+
// Change display setting
|
90
|
+
dm.dmSize = sizeof(DEVMODE);
|
91
|
+
if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
|
92
|
+
throw std::runtime_error("Could not set fullscreen mode");
|
93
|
+
}
|
94
|
+
|
95
|
+
void setupVSync()
|
96
|
+
{
|
97
|
+
char* extensions = (char*)glGetString(GL_EXTENSIONS);
|
98
|
+
if (!strstr(extensions, "WGL_EXT_swap_control"))
|
99
|
+
return;
|
100
|
+
typedef void (APIENTRY *PFNWGLEXTSWAPCONTROLPROC) (int);
|
101
|
+
PFNWGLEXTSWAPCONTROLPROC wglSwapIntervalEXT =
|
102
|
+
(PFNWGLEXTSWAPCONTROLPROC) wglGetProcAddress("wglSwapIntervalEXT");
|
103
|
+
if (!wglSwapIntervalEXT)
|
104
|
+
return;
|
105
|
+
wglSwapIntervalEXT(1);
|
106
|
+
}
|
107
|
+
|
108
|
+
LRESULT CALLBACK windowProc(HWND wnd, UINT message, WPARAM wparam,
|
109
|
+
LPARAM lparam)
|
110
|
+
{
|
111
|
+
LONG_PTR lptr = GetWindowLongPtr(wnd, GWLP_USERDATA);
|
112
|
+
|
113
|
+
if (lptr)
|
114
|
+
{
|
115
|
+
Window* obj = reinterpret_cast<Window*>(lptr);
|
116
|
+
return obj->handleMessage(message, wparam, lparam);
|
117
|
+
}
|
118
|
+
else
|
119
|
+
return DefWindowProc(wnd, message, wparam, lparam);
|
120
|
+
}
|
121
|
+
|
122
|
+
LPCTSTR windowClass()
|
123
|
+
{
|
124
|
+
static LPCTSTR name = 0;
|
125
|
+
if (name)
|
126
|
+
return name;
|
127
|
+
|
128
|
+
WNDCLASS wc;
|
129
|
+
wc.lpszClassName = L"Gosu::Window";
|
130
|
+
wc.style = CS_OWNDC;
|
131
|
+
wc.lpfnWndProc = windowProc;
|
132
|
+
wc.cbClsExtra = 0;
|
133
|
+
wc.cbWndExtra = 0;
|
134
|
+
wc.hInstance = Win::instance();
|
135
|
+
wc.hIcon = 0;
|
136
|
+
wc.hCursor = 0;
|
137
|
+
wc.hbrBackground = 0;
|
138
|
+
wc.lpszMenuName = 0;
|
139
|
+
|
140
|
+
name = reinterpret_cast<LPCTSTR>(::RegisterClass(&wc));
|
141
|
+
Win::check(name, "registering a window class");
|
142
|
+
return name;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
struct Gosu::Window::Impl
|
148
|
+
{
|
149
|
+
HWND handle;
|
150
|
+
HDC hdc;
|
151
|
+
boost::scoped_ptr<Graphics> graphics;
|
152
|
+
boost::scoped_ptr<Audio> audio;
|
153
|
+
boost::scoped_ptr<Input> input;
|
154
|
+
double updateInterval;
|
155
|
+
bool iconified;
|
156
|
+
|
157
|
+
Impl()
|
158
|
+
: handle(0), hdc(0), iconified(false)
|
159
|
+
{
|
160
|
+
}
|
161
|
+
|
162
|
+
~Impl()
|
163
|
+
{
|
164
|
+
if (hdc)
|
165
|
+
ReleaseDC(handle, hdc);
|
166
|
+
if (handle)
|
167
|
+
DestroyWindow(handle);
|
168
|
+
}
|
169
|
+
};
|
170
|
+
|
171
|
+
Gosu::Window::Window(unsigned width, unsigned height, bool fullscreen,
|
172
|
+
double updateInterval)
|
173
|
+
: pimpl(new Impl)
|
174
|
+
{
|
175
|
+
// Select window styles depending on mode.fullscreen.
|
176
|
+
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
177
|
+
DWORD styleEx = WS_EX_APPWINDOW;
|
178
|
+
if (fullscreen)
|
179
|
+
{
|
180
|
+
style |= WS_POPUP;
|
181
|
+
styleEx |= WS_EX_TOPMOST;
|
182
|
+
}
|
183
|
+
else
|
184
|
+
{
|
185
|
+
style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
186
|
+
styleEx |= WS_EX_WINDOWEDGE;
|
187
|
+
}
|
188
|
+
|
189
|
+
pimpl->handle = CreateWindowEx(styleEx, windowClass(), 0, style,
|
190
|
+
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
|
191
|
+
Win::instance(), 0);
|
192
|
+
Win::check(pimpl->handle);
|
193
|
+
|
194
|
+
pimpl->hdc = GetDC(handle());
|
195
|
+
Win::check(pimpl->hdc);
|
196
|
+
|
197
|
+
PIXELFORMATDESCRIPTOR pfd;
|
198
|
+
ZeroMemory(&pfd, sizeof pfd);
|
199
|
+
pfd.nSize = sizeof pfd;
|
200
|
+
pfd.nVersion = 1;
|
201
|
+
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
202
|
+
pfd.iLayerType = PFD_MAIN_PLANE;
|
203
|
+
pfd.iPixelType = PFD_TYPE_RGBA;
|
204
|
+
pfd.cColorBits = 32;
|
205
|
+
int pf = ChoosePixelFormat(pimpl->hdc, &pfd);
|
206
|
+
Win::check(pf);
|
207
|
+
Win::check(SetPixelFormat(pimpl->hdc, pf, &pfd));
|
208
|
+
|
209
|
+
HGLRC hrc = Win::check(wglCreateContext(pimpl->hdc), "creating rendering context");
|
210
|
+
Win::check(wglMakeCurrent(pimpl->hdc, hrc), "selecting the rendering context");
|
211
|
+
|
212
|
+
setupVSync();
|
213
|
+
|
214
|
+
SetLastError(0);
|
215
|
+
SetWindowLongPtr(handle(), GWLP_USERDATA,
|
216
|
+
reinterpret_cast<LONG_PTR>(this));
|
217
|
+
if (GetLastError() != 0)
|
218
|
+
Win::throwLastError("setting the window's GWLP_USERDATA pointer");
|
219
|
+
|
220
|
+
// Determine the size the window needs to have.
|
221
|
+
RECT rc = { 0, 0, width, height };
|
222
|
+
AdjustWindowRectEx(&rc, style, FALSE, styleEx);
|
223
|
+
unsigned windowW = rc.right - rc.left;
|
224
|
+
unsigned windowH = rc.bottom - rc.top;
|
225
|
+
|
226
|
+
int windowX = 0;
|
227
|
+
int windowY = 0;
|
228
|
+
|
229
|
+
if (!fullscreen)
|
230
|
+
{
|
231
|
+
// Center the window.
|
232
|
+
HWND desktopWindow = GetDesktopWindow();
|
233
|
+
RECT desktopRect;
|
234
|
+
GetClientRect(desktopWindow, &desktopRect);
|
235
|
+
int desktopW = desktopRect.right - desktopRect.left;
|
236
|
+
int desktopH = desktopRect.bottom - desktopRect.top;
|
237
|
+
windowX = (desktopW - windowW) / 2;
|
238
|
+
windowY = (desktopH - windowH) / 2;
|
239
|
+
}
|
240
|
+
|
241
|
+
MoveWindow(handle(), windowX, windowY, windowW, windowH, false);
|
242
|
+
|
243
|
+
pimpl->graphics.reset(new Gosu::Graphics(width, height, fullscreen));
|
244
|
+
pimpl->input.reset(new Gosu::Input(handle()));
|
245
|
+
input().onButtonDown = boost::bind(&Window::buttonDown, this, _1);
|
246
|
+
input().onButtonUp = boost::bind(&Window::buttonUp, this, _1);
|
247
|
+
|
248
|
+
pimpl->updateInterval = updateInterval;
|
249
|
+
}
|
250
|
+
|
251
|
+
Gosu::Window::~Window()
|
252
|
+
{
|
253
|
+
wglMakeCurrent(0, 0);
|
254
|
+
}
|
255
|
+
|
256
|
+
std::wstring Gosu::Window::caption() const
|
257
|
+
{
|
258
|
+
int bufLen = GetWindowTextLength(handle()) + 1;
|
259
|
+
|
260
|
+
if (bufLen < 2)
|
261
|
+
return L"";
|
262
|
+
|
263
|
+
std::vector<TCHAR> buf(bufLen);
|
264
|
+
GetWindowText(handle(), &buf.front(), bufLen);
|
265
|
+
return &buf.front();
|
266
|
+
}
|
267
|
+
|
268
|
+
void Gosu::Window::setCaption(const std::wstring& value)
|
269
|
+
{
|
270
|
+
SetWindowText(handle(), value.c_str());
|
271
|
+
}
|
272
|
+
|
273
|
+
namespace GosusDarkSide
|
274
|
+
{
|
275
|
+
// TODO: Find a way for this to fit into Gosu's design.
|
276
|
+
// This can point to a function that wants to be called every
|
277
|
+
// frame, e.g. rb_thread_schedule.
|
278
|
+
typedef void (*HookOfHorror)();
|
279
|
+
HookOfHorror oncePerTick = 0;
|
280
|
+
}
|
281
|
+
|
282
|
+
void Gosu::Window::show()
|
283
|
+
{
|
284
|
+
int w = graphics().width(), h = graphics().height(), bpp = 32, rr = 60;
|
285
|
+
if (pimpl->graphics->fullscreen())
|
286
|
+
setVideoMode(findClosestVideoMode(&w, &h, &bpp, &rr));
|
287
|
+
ShowWindow(handle(), SW_SHOW);
|
288
|
+
try
|
289
|
+
{
|
290
|
+
Win::processMessages();
|
291
|
+
|
292
|
+
unsigned lastTick = 0;
|
293
|
+
bool lastFrameSkipped = false;
|
294
|
+
|
295
|
+
for (;;)
|
296
|
+
{
|
297
|
+
Win::processMessages();
|
298
|
+
|
299
|
+
if (GosusDarkSide::oncePerTick) GosusDarkSide::oncePerTick();
|
300
|
+
|
301
|
+
if (!::IsWindowVisible(handle()))
|
302
|
+
return;
|
303
|
+
|
304
|
+
unsigned ms = milliseconds();
|
305
|
+
|
306
|
+
if (ms < lastTick || ms - lastTick >= pimpl->updateInterval)
|
307
|
+
{
|
308
|
+
lastTick = ms;
|
309
|
+
input().update();
|
310
|
+
update();
|
311
|
+
::InvalidateRect(handle(), 0, FALSE);
|
312
|
+
lastFrameSkipped = false;
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
316
|
+
catch (...)
|
317
|
+
{
|
318
|
+
close();
|
319
|
+
throw;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
void Gosu::Window::close()
|
324
|
+
{
|
325
|
+
ShowWindow(handle(), SW_HIDE);
|
326
|
+
if (graphics().fullscreen())
|
327
|
+
ChangeDisplaySettings(NULL, CDS_FULLSCREEN);
|
328
|
+
}
|
329
|
+
|
330
|
+
const Gosu::Graphics& Gosu::Window::graphics() const
|
331
|
+
{
|
332
|
+
return *pimpl->graphics;
|
333
|
+
}
|
334
|
+
|
335
|
+
Gosu::Graphics& Gosu::Window::graphics()
|
336
|
+
{
|
337
|
+
return *pimpl->graphics;
|
338
|
+
}
|
339
|
+
|
340
|
+
const Gosu::Audio& Gosu::Window::audio() const
|
341
|
+
{
|
342
|
+
if (!pimpl->audio)
|
343
|
+
pimpl->audio.reset(new Gosu::Audio(handle()));
|
344
|
+
return *pimpl->audio;
|
345
|
+
}
|
346
|
+
|
347
|
+
Gosu::Audio& Gosu::Window::audio()
|
348
|
+
{
|
349
|
+
if (!pimpl->audio)
|
350
|
+
pimpl->audio.reset(new Gosu::Audio(handle()));
|
351
|
+
return *pimpl->audio;
|
352
|
+
}
|
353
|
+
|
354
|
+
const Gosu::Input& Gosu::Window::input() const
|
355
|
+
{
|
356
|
+
return *pimpl->input;
|
357
|
+
}
|
358
|
+
|
359
|
+
Gosu::Input& Gosu::Window::input()
|
360
|
+
{
|
361
|
+
return *pimpl->input;
|
362
|
+
}
|
363
|
+
|
364
|
+
HWND Gosu::Window::handle() const
|
365
|
+
{
|
366
|
+
return pimpl->handle;
|
367
|
+
}
|
368
|
+
|
369
|
+
LRESULT Gosu::Window::handleMessage(UINT message, WPARAM wparam, LPARAM lparam)
|
370
|
+
{
|
371
|
+
if (message == WM_SETFOCUS && graphics().fullscreen() && IsWindowVisible(pimpl->handle))
|
372
|
+
{
|
373
|
+
if (pimpl->iconified)
|
374
|
+
{
|
375
|
+
OpenIcon(pimpl->handle);
|
376
|
+
int w = graphics().width(), h = graphics().height(), bpp = 32, rr = 60;
|
377
|
+
setVideoMode(findClosestVideoMode(&w, &h, &bpp, &rr));
|
378
|
+
pimpl->iconified = false;
|
379
|
+
}
|
380
|
+
return 0;
|
381
|
+
}
|
382
|
+
|
383
|
+
if (message == WM_KILLFOCUS && graphics().fullscreen() && IsWindowVisible(pimpl->handle))
|
384
|
+
{
|
385
|
+
if (!pimpl->iconified)
|
386
|
+
{
|
387
|
+
ChangeDisplaySettings(NULL, CDS_FULLSCREEN);
|
388
|
+
CloseWindow(pimpl->handle);
|
389
|
+
pimpl->iconified = true;
|
390
|
+
}
|
391
|
+
return 0;
|
392
|
+
}
|
393
|
+
|
394
|
+
if (message == WM_CLOSE)
|
395
|
+
{
|
396
|
+
close();
|
397
|
+
return 0;
|
398
|
+
}
|
399
|
+
|
400
|
+
if (message == WM_PAINT)
|
401
|
+
{
|
402
|
+
if (pimpl->graphics && graphics().begin())
|
403
|
+
{
|
404
|
+
try
|
405
|
+
{
|
406
|
+
draw();
|
407
|
+
}
|
408
|
+
catch (...)
|
409
|
+
{
|
410
|
+
graphics().end();
|
411
|
+
throw;
|
412
|
+
}
|
413
|
+
graphics().end();
|
414
|
+
}
|
415
|
+
SwapBuffers(pimpl->hdc);
|
416
|
+
ValidateRect(handle(), 0);
|
417
|
+
return 0;
|
418
|
+
}
|
419
|
+
|
420
|
+
if (message == WM_SETCURSOR && LOWORD(lparam) == HTCLIENT)
|
421
|
+
{
|
422
|
+
SetCursor(0);
|
423
|
+
return TRUE;
|
424
|
+
}
|
425
|
+
|
426
|
+
if (message == WM_SYSCOMMAND)
|
427
|
+
{
|
428
|
+
switch(wparam)
|
429
|
+
{
|
430
|
+
case SC_SCREENSAVE:
|
431
|
+
case SC_MONITORPOWER:
|
432
|
+
if (graphics().fullscreen())
|
433
|
+
return 0;
|
434
|
+
else
|
435
|
+
break;
|
436
|
+
case SC_KEYMENU:
|
437
|
+
return 0;
|
438
|
+
}
|
439
|
+
}
|
440
|
+
|
441
|
+
if (pimpl->input && input().textInput() && input().textInput()->feedMessage(message, wparam, lparam))
|
442
|
+
{
|
443
|
+
return 0;
|
444
|
+
}
|
445
|
+
|
446
|
+
return DefWindowProc(handle(), message, wparam, lparam);
|
447
|
+
}
|
@@ -0,0 +1,392 @@
|
|
1
|
+
// While (re)writing this file, I have been looking at many other libraries since all the
|
2
|
+
// "official" documentation was horrible, at least those parts that I was able to find.
|
3
|
+
// Kudos to the Pyglet folks (http://www.pyglet.org/) who wrote code that was much easier to
|
4
|
+
// understand than that!
|
5
|
+
|
6
|
+
#include <Gosu/Window.hpp>
|
7
|
+
#include <Gosu/Timing.hpp>
|
8
|
+
#include <Gosu/Utility.hpp>
|
9
|
+
#include <Gosu/Input.hpp>
|
10
|
+
#include <Gosu/Graphics.hpp>
|
11
|
+
#include <Gosu/Audio.hpp>
|
12
|
+
#include <boost/bind.hpp>
|
13
|
+
#include <stdexcept>
|
14
|
+
#include <algorithm>
|
15
|
+
#include <vector>
|
16
|
+
|
17
|
+
#include <GL/glx.h>
|
18
|
+
#include <X11/Xlib.h>
|
19
|
+
#include <X11/Xutil.h>
|
20
|
+
#include "X11vroot.h"
|
21
|
+
|
22
|
+
namespace
|
23
|
+
{
|
24
|
+
template<typename T>
|
25
|
+
class scoped_resource
|
26
|
+
{
|
27
|
+
T* pointer;
|
28
|
+
typedef boost::function<void(T*)> Deleter;
|
29
|
+
Deleter deleter;
|
30
|
+
|
31
|
+
public:
|
32
|
+
scoped_resource(T* pointer, const Deleter& deleter)
|
33
|
+
: pointer(pointer), deleter(deleter)
|
34
|
+
{
|
35
|
+
}
|
36
|
+
|
37
|
+
void reset(T* newPointer = 0)
|
38
|
+
{
|
39
|
+
if (pointer)
|
40
|
+
deleter(pointer);
|
41
|
+
pointer = newPointer;
|
42
|
+
}
|
43
|
+
|
44
|
+
T* get() const
|
45
|
+
{
|
46
|
+
return pointer;
|
47
|
+
}
|
48
|
+
|
49
|
+
T* operator->() const
|
50
|
+
{
|
51
|
+
return get();
|
52
|
+
}
|
53
|
+
|
54
|
+
~scoped_resource()
|
55
|
+
{
|
56
|
+
reset(0);
|
57
|
+
}
|
58
|
+
};
|
59
|
+
}
|
60
|
+
|
61
|
+
struct Gosu::Window::Impl
|
62
|
+
{
|
63
|
+
boost::scoped_ptr<Graphics> graphics;
|
64
|
+
boost::scoped_ptr<Input> input;
|
65
|
+
boost::scoped_ptr<Audio> audio;
|
66
|
+
|
67
|
+
::Display* display;
|
68
|
+
|
69
|
+
bool mapped, showing, active;
|
70
|
+
|
71
|
+
::GLXContext context;
|
72
|
+
::Window window;
|
73
|
+
::XVisualInfo* visual;
|
74
|
+
|
75
|
+
// Last set title
|
76
|
+
std::wstring title;
|
77
|
+
// Last known position
|
78
|
+
int x, y;
|
79
|
+
// Last known size
|
80
|
+
int width, height;
|
81
|
+
|
82
|
+
|
83
|
+
double updateInterval;
|
84
|
+
bool fullscreen;
|
85
|
+
|
86
|
+
Impl(unsigned width, unsigned height, unsigned fullscreen, double updateInterval)
|
87
|
+
: mapped(false), showing(false), active(true),
|
88
|
+
x(0), y(0), width(width), height(height),
|
89
|
+
updateInterval(updateInterval), fullscreen(fullscreen)
|
90
|
+
{
|
91
|
+
|
92
|
+
}
|
93
|
+
|
94
|
+
void executeAndWait(boost::function<void(Display*, ::Window)> function, int forMessage)
|
95
|
+
{
|
96
|
+
XSelectInput(display, window, StructureNotifyMask);
|
97
|
+
function(display, window);
|
98
|
+
while (true)
|
99
|
+
{
|
100
|
+
::XEvent event;
|
101
|
+
XNextEvent(display, &event);
|
102
|
+
if (event.type == forMessage)
|
103
|
+
break;
|
104
|
+
}
|
105
|
+
XSelectInput(display, window, 0x1ffffff & ~PointerMotionHintMask & ~ResizeRedirectMask);
|
106
|
+
}
|
107
|
+
|
108
|
+
void doTick(Window* window)
|
109
|
+
{
|
110
|
+
while (::XPending(display))
|
111
|
+
{
|
112
|
+
::XEvent event;
|
113
|
+
XNextEvent(display, &event);
|
114
|
+
|
115
|
+
// Override redirect fix (thanks for Pyglet folks again):
|
116
|
+
if (event.type == ButtonPress && fullscreen && !active)
|
117
|
+
XSetInputFocus(display, this->window, RevertToParent, CurrentTime);
|
118
|
+
|
119
|
+
if (!window->input().feedXEvent(event, window))
|
120
|
+
{
|
121
|
+
if (event.type == ConfigureNotify)
|
122
|
+
{
|
123
|
+
// Only boring stuff to do? Let's do something random:
|
124
|
+
glXMakeCurrent(display, this->window, context);
|
125
|
+
}
|
126
|
+
else if (event.type == ClientMessage)
|
127
|
+
{
|
128
|
+
if (static_cast<unsigned>(event.xclient.data.l[0]) ==
|
129
|
+
XInternAtom(display, "WM_DELETE_WINDOW", false))
|
130
|
+
window->close();
|
131
|
+
}
|
132
|
+
else if (event.type == FocusIn)
|
133
|
+
active = true;
|
134
|
+
else if (event.type == FocusOut)
|
135
|
+
active = false;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
if (window->graphics().begin(Colors::black))
|
140
|
+
{
|
141
|
+
window->draw();
|
142
|
+
window->graphics().end();
|
143
|
+
glXSwapBuffers(display, this->window);
|
144
|
+
}
|
145
|
+
|
146
|
+
window->input().update();
|
147
|
+
window->update();
|
148
|
+
}
|
149
|
+
};
|
150
|
+
|
151
|
+
Gosu::Window::Window(unsigned width, unsigned height, bool fullscreen,
|
152
|
+
double updateInterval)
|
153
|
+
: pimpl(new Impl(width, height, fullscreen, updateInterval))
|
154
|
+
{
|
155
|
+
pimpl->display = XOpenDisplay(NULL);
|
156
|
+
if (!pimpl->display)
|
157
|
+
throw std::runtime_error("Cannot find display");
|
158
|
+
|
159
|
+
::Window root = DefaultRootWindow(pimpl->display);
|
160
|
+
|
161
|
+
// Setup GLX visual
|
162
|
+
static int glxAttributes[] =
|
163
|
+
{
|
164
|
+
GLX_RGBA,
|
165
|
+
GLX_DOUBLEBUFFER,
|
166
|
+
GLX_RED_SIZE, 1,
|
167
|
+
GLX_GREEN_SIZE, 1,
|
168
|
+
GLX_BLUE_SIZE, 1,
|
169
|
+
GLX_DEPTH_SIZE, 1,
|
170
|
+
None
|
171
|
+
};
|
172
|
+
pimpl->visual = glXChooseVisual(pimpl->display, DefaultScreen(pimpl->display), glxAttributes);
|
173
|
+
|
174
|
+
// Create GLX context
|
175
|
+
pimpl->context = glXCreateContext(pimpl->display, pimpl->visual, 0, GL_TRUE);
|
176
|
+
|
177
|
+
// Set up window attributes (& mask)
|
178
|
+
XSetWindowAttributes windowAttributes;
|
179
|
+
windowAttributes.colormap = XCreateColormap(pimpl->display, root, pimpl->visual->visual, AllocNone);
|
180
|
+
windowAttributes.bit_gravity = NorthWestGravity;
|
181
|
+
windowAttributes.background_pixel = 0;
|
182
|
+
unsigned mask = CWColormap | CWBitGravity | CWBackPixel;
|
183
|
+
|
184
|
+
// Create window
|
185
|
+
pimpl->window = XCreateWindow(pimpl->display, root, 0, 0, width, height, 0,
|
186
|
+
pimpl->visual->depth, InputOutput, pimpl->visual->visual,
|
187
|
+
mask, &windowAttributes);
|
188
|
+
|
189
|
+
// Request a close button for the window
|
190
|
+
Atom atoms[] = { XInternAtom(pimpl->display, "WM_DELETE_WINDOW", false) };
|
191
|
+
XSetWMProtocols(pimpl->display, pimpl->window, atoms, 1);
|
192
|
+
|
193
|
+
Screen* screen = XScreenOfDisplay(pimpl->display,
|
194
|
+
DefaultScreen(pimpl->display));
|
195
|
+
|
196
|
+
if (fullscreen)
|
197
|
+
{
|
198
|
+
pimpl->width = screen->width;
|
199
|
+
pimpl->height = screen->height;
|
200
|
+
XMoveResizeWindow(pimpl->display, pimpl->window, 0, 0,
|
201
|
+
screen->width, screen->height);
|
202
|
+
|
203
|
+
XSetWindowAttributes windowAttributes;
|
204
|
+
windowAttributes.override_redirect = true;
|
205
|
+
unsigned mask = CWOverrideRedirect;
|
206
|
+
XChangeWindowAttributes(pimpl->display, pimpl->window, mask, &windowAttributes);
|
207
|
+
}
|
208
|
+
else
|
209
|
+
; // Window already has requested size
|
210
|
+
|
211
|
+
// Set window to be non resizable
|
212
|
+
scoped_resource<XSizeHints> sizeHints(XAllocSizeHints(), XFree);
|
213
|
+
sizeHints->flags = PMinSize | PMaxSize;
|
214
|
+
sizeHints->min_width = sizeHints->max_width = pimpl->width;
|
215
|
+
sizeHints->min_height = sizeHints->max_height = pimpl->height;
|
216
|
+
XSetWMNormalHints(pimpl->display, pimpl->window, sizeHints.get());
|
217
|
+
sizeHints.reset();
|
218
|
+
|
219
|
+
// TODO: Window style (_MOTIF_WM_HINTS)?
|
220
|
+
|
221
|
+
XColor black, dummy;
|
222
|
+
XAllocNamedColor(pimpl->display, screen->cmap, "black", &black, &dummy);
|
223
|
+
char emptyData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
224
|
+
Pixmap emptyBitmap =
|
225
|
+
XCreateBitmapFromData(pimpl->display, pimpl->window, emptyData, 8, 8);
|
226
|
+
Cursor emptyCursor = XCreatePixmapCursor(pimpl->display, emptyBitmap,
|
227
|
+
emptyBitmap, &black, &black, 0, 0);
|
228
|
+
XDefineCursor(pimpl->display, pimpl->window, emptyCursor);
|
229
|
+
XFreeCursor(pimpl->display, emptyCursor);
|
230
|
+
|
231
|
+
// Must be current already so that Graphics' constructor can set up things
|
232
|
+
glXMakeCurrent(pimpl->display, pimpl->window, pimpl->context);
|
233
|
+
|
234
|
+
// Now set up major Gosu components
|
235
|
+
pimpl->graphics.reset(new Gosu::Graphics(pimpl->width, pimpl->height, fullscreen));
|
236
|
+
pimpl->input.reset(new Gosu::Input(pimpl->display));
|
237
|
+
input().onButtonDown = boost::bind(&Window::buttonDown, this, _1);
|
238
|
+
input().onButtonUp = boost::bind(&Window::buttonUp, this, _1);
|
239
|
+
|
240
|
+
// Fix coordinates for fullscreen screen-scaling
|
241
|
+
if (fullscreen)
|
242
|
+
{
|
243
|
+
graphics().setResolution(width, height);
|
244
|
+
input().setMouseFactors(1.0 * width / pimpl->width,
|
245
|
+
1.0 * height / pimpl->height);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
Gosu::Window::~Window()
|
250
|
+
{
|
251
|
+
XDestroyWindow(pimpl->display, pimpl->window);
|
252
|
+
XSync(pimpl->display, false);
|
253
|
+
}
|
254
|
+
|
255
|
+
std::wstring Gosu::Window::caption() const
|
256
|
+
{
|
257
|
+
return pimpl->title;
|
258
|
+
}
|
259
|
+
|
260
|
+
void Gosu::Window::setCaption(const std::wstring& caption)
|
261
|
+
{
|
262
|
+
// TODO: Update to _NET_WM_NAME
|
263
|
+
|
264
|
+
pimpl->title = caption;
|
265
|
+
|
266
|
+
// TODO: Why?!
|
267
|
+
//if (!pimpl->showing)
|
268
|
+
// return;
|
269
|
+
|
270
|
+
std::string tmpString(pimpl->title.begin(), pimpl->title.end());
|
271
|
+
std::vector<char> title(pimpl->title.size() + 1);
|
272
|
+
std::copy(tmpString.begin(), tmpString.end(), title.begin());
|
273
|
+
title.back() = 0;
|
274
|
+
|
275
|
+
XTextProperty titleprop;
|
276
|
+
char* titlePtr = &title[0];
|
277
|
+
XStringListToTextProperty(&titlePtr, 1, &titleprop);
|
278
|
+
|
279
|
+
XSetWMName(pimpl->display, pimpl->window, &titleprop);
|
280
|
+
XFree(titleprop.value);
|
281
|
+
XSync(pimpl->display, false);
|
282
|
+
}
|
283
|
+
|
284
|
+
namespace GosusDarkSide
|
285
|
+
{
|
286
|
+
// TODO: Find a way for this to fit into Gosu's design.
|
287
|
+
// This can point to a function that wants to be called every
|
288
|
+
// frame, e.g. rb_thread_schedule.
|
289
|
+
typedef void (*HookOfHorror)();
|
290
|
+
HookOfHorror oncePerTick = 0;
|
291
|
+
}
|
292
|
+
|
293
|
+
// TODO: Some exception safety
|
294
|
+
|
295
|
+
void Gosu::Window::show()
|
296
|
+
{
|
297
|
+
// Map window
|
298
|
+
pimpl->executeAndWait(XMapRaised, MapNotify);
|
299
|
+
pimpl->mapped = true;
|
300
|
+
|
301
|
+
// Make glx current
|
302
|
+
glXMakeCurrent(pimpl->display, pimpl->window, pimpl->context);
|
303
|
+
|
304
|
+
if (pimpl->fullscreen)
|
305
|
+
XSetInputFocus(pimpl->display, pimpl->window, RevertToParent, CurrentTime);
|
306
|
+
|
307
|
+
setCaption(pimpl->title);
|
308
|
+
|
309
|
+
unsigned startTime, endTime;
|
310
|
+
|
311
|
+
pimpl->showing = true;
|
312
|
+
while (pimpl->showing)
|
313
|
+
{
|
314
|
+
startTime = milliseconds();
|
315
|
+
pimpl->doTick(this);
|
316
|
+
if (GosusDarkSide::oncePerTick) GosusDarkSide::oncePerTick();
|
317
|
+
endTime = milliseconds();
|
318
|
+
|
319
|
+
if (startTime < endTime && (endTime - startTime) < pimpl->updateInterval)
|
320
|
+
sleep(pimpl->updateInterval - (endTime - startTime));
|
321
|
+
}
|
322
|
+
|
323
|
+
glXMakeCurrent(pimpl->display, 0, 0);
|
324
|
+
pimpl->executeAndWait(XUnmapWindow, UnmapNotify);
|
325
|
+
pimpl->mapped = false;
|
326
|
+
}
|
327
|
+
|
328
|
+
void Gosu::Window::close()
|
329
|
+
{
|
330
|
+
pimpl->showing = false;
|
331
|
+
}
|
332
|
+
|
333
|
+
const Gosu::Graphics& Gosu::Window::graphics() const
|
334
|
+
{
|
335
|
+
return *pimpl->graphics;
|
336
|
+
}
|
337
|
+
|
338
|
+
Gosu::Graphics& Gosu::Window::graphics()
|
339
|
+
{
|
340
|
+
return *pimpl->graphics;
|
341
|
+
}
|
342
|
+
|
343
|
+
const Gosu::Audio& Gosu::Window::audio() const
|
344
|
+
{
|
345
|
+
if (!pimpl->audio)
|
346
|
+
pimpl->audio.reset(new Gosu::Audio());
|
347
|
+
return *pimpl->audio;
|
348
|
+
}
|
349
|
+
|
350
|
+
Gosu::Audio& Gosu::Window::audio()
|
351
|
+
{
|
352
|
+
if (!pimpl->audio)
|
353
|
+
pimpl->audio.reset(new Gosu::Audio());
|
354
|
+
return *pimpl->audio;
|
355
|
+
}
|
356
|
+
|
357
|
+
const Gosu::Input& Gosu::Window::input() const
|
358
|
+
{
|
359
|
+
return *pimpl->input;
|
360
|
+
}
|
361
|
+
|
362
|
+
Gosu::Input& Gosu::Window::input()
|
363
|
+
{
|
364
|
+
return *pimpl->input;
|
365
|
+
}
|
366
|
+
|
367
|
+
namespace
|
368
|
+
{
|
369
|
+
void makeCurrentContext(Display* dpy, GLXDrawable drawable, GLXContext context) {
|
370
|
+
if (!glXMakeCurrent(dpy, drawable, context))
|
371
|
+
printf("glXMakeCurrent failed\n");
|
372
|
+
}
|
373
|
+
|
374
|
+
void releaseContext(Display* dpy, GLXContext context) {
|
375
|
+
glXDestroyContext(dpy, context);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
|
379
|
+
Gosu::Window::SharedContext Gosu::Window::createSharedContext() {
|
380
|
+
const char* displayName = DisplayString( pimpl->display );
|
381
|
+
Display* dpy2 = XOpenDisplay( displayName );
|
382
|
+
if (!dpy2)
|
383
|
+
throw std::runtime_error("Could not duplicate X display");
|
384
|
+
|
385
|
+
GLXContext ctx = glXCreateContext(dpy2, pimpl->visual, pimpl->context, True);
|
386
|
+
if (!ctx)
|
387
|
+
throw std::runtime_error("Could not create shared GLX context");
|
388
|
+
|
389
|
+
return SharedContext(
|
390
|
+
new boost::function<void()>(boost::bind(makeCurrentContext, dpy2, pimpl->window, ctx)),
|
391
|
+
boost::bind(releaseContext, dpy2, ctx));
|
392
|
+
}
|