1 /*
2 * ppui/sdl/DisplayDevice_SDL.cpp
3 *
4 * Copyright 2009 Peter Barth, Christopher O'Neill, Dale Whinham
5 *
6 * This file is part of Milkytracker.
7 *
8 * Milkytracker is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Milkytracker is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Milkytracker. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include "DisplayDevice_SDL.h"
24 #include "Graphics.h"
25
CreateWindow(pp_int32 & w,pp_int32 & h,pp_int32 & bpp,Uint32 flags)26 SDL_Window* PPDisplayDevice::CreateWindow(pp_int32& w, pp_int32& h, pp_int32& bpp, Uint32 flags)
27 {
28 size_t namelen = 0;
29 char rendername[256] = { 0 };
30 PFNGLGETSTRINGPROC glGetStringAPI = NULL;
31
32 for (int it = 0; it < SDL_GetNumRenderDrivers(); it++)
33 {
34 SDL_RendererInfo info;
35 SDL_GetRenderDriverInfo(it, &info);
36
37 namelen += strlen(info.name) + 1;
38 strncat(rendername, info.name, sizeof(rendername) - namelen);
39 strncat(rendername, " ", sizeof(rendername) - namelen);
40
41 if (strncmp("opengles2", info.name, 9) == 0)
42 {
43 drv_index = it;
44 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
45 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
46 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
47 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
48 }
49 }
50
51 // Create SDL window
52 SDL_Window* theWindow = SDL_CreateWindow("MilkyTracker", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL | flags);
53
54 if (theWindow == NULL)
55 {
56 fprintf(stderr, "SDL: SDL_CreateWindow (width: %d, height: %d) failed: %s\n", w, h, SDL_GetError());
57 fprintf(stderr, "Retrying with default size...");
58
59 w = getDefaultWidth();
60 h = getDefaultHeight();
61
62 theWindow = SDL_CreateWindow("MilkyTracker", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL | flags);
63
64 if (theWindow == NULL)
65 {
66 fprintf(stderr, "SDL: SDL_CreateWindow (width: %d, height: %d) failed: %s\n", w, h, SDL_GetError());
67 fprintf(stderr, "Giving up.\n");
68 return NULL;
69 }
70 }
71
72 SDL_GLContext ctx = SDL_GL_CreateContext(theWindow);
73 SDL_GL_MakeCurrent(theWindow, ctx);
74
75 glGetStringAPI = (PFNGLGETSTRINGPROC)SDL_GL_GetProcAddress("glGetString");
76
77 fprintf(stdout, "Available Renderers: %s\n", rendername);
78 if (glGetStringAPI)
79 {
80 fprintf(stdout, "Vendor : %s\n", glGetStringAPI(GL_VENDOR));
81 fprintf(stdout, "Renderer : %s\n", glGetStringAPI(GL_RENDERER));
82 fprintf(stdout, "Version : %s\n", glGetStringAPI(GL_VERSION));
83 #ifdef DEBUG
84 fprintf(stdout, "Extensions : %s\n", glGetStringAPI(GL_EXTENSIONS));
85 #endif
86 }
87 // Prevent window from being resized below minimum
88 SDL_SetWindowMinimumSize(theWindow, w, h);
89 fprintf(stderr, "SDL: Minimum window size set to %dx%d.\n", w, h);
90
91 return theWindow;
92 }
93
PPDisplayDevice(pp_int32 width,pp_int32 height,pp_int32 scaleFactor,pp_int32 bpp,bool fullScreen,Orientations theOrientation)94 PPDisplayDevice::PPDisplayDevice(pp_int32 width,
95 pp_int32 height,
96 pp_int32 scaleFactor,
97 pp_int32 bpp,
98 bool fullScreen,
99 Orientations theOrientation/* = ORIENTATION_NORMAL*/) :
100 PPDisplayDeviceBase(width, height, scaleFactor),
101 realWidth(width), realHeight(height),
102 orientation(theOrientation)
103 {
104 adjust(realWidth, realHeight);
105
106 bFullScreen = fullScreen;
107
108 drv_index = -1;
109
110 initMousePointers();
111 }
112
~PPDisplayDevice()113 PPDisplayDevice::~PPDisplayDevice()
114 {
115 delete currentGraphics;
116 }
117
adjust(pp_int32 & x,pp_int32 & y)118 void PPDisplayDevice::adjust(pp_int32& x, pp_int32& y)
119 {
120 switch (orientation)
121 {
122 case ORIENTATION_NORMAL:
123 break;
124
125 case ORIENTATION_ROTATE90CCW:
126 case ORIENTATION_ROTATE90CW:
127 {
128 pp_int32 h = x;
129 x = y;
130 y = h;
131 break;
132 }
133 }
134
135 x *= scaleFactor;
136 y *= scaleFactor;
137 }
138
transform(pp_int32 & x,pp_int32 & y)139 void PPDisplayDevice::transform(pp_int32& x, pp_int32& y)
140 {
141 pp_int32 h;
142
143 switch (orientation)
144 {
145 case ORIENTATION_NORMAL:
146 break;
147
148 case ORIENTATION_ROTATE90CW:
149 h = x;
150 x = y;
151 y = realWidth - 1 - h;
152 break;
153
154 case ORIENTATION_ROTATE90CCW:
155 h = x;
156 x = realHeight - 1 - y;
157 y = h;
158 break;
159 }
160 }
161
transformInverse(pp_int32 & x,pp_int32 & y)162 void PPDisplayDevice::transformInverse(pp_int32& x, pp_int32& y)
163 {
164 pp_int32 h;
165
166 switch (orientation)
167 {
168 case ORIENTATION_NORMAL:
169 break;
170
171 case ORIENTATION_ROTATE90CW:
172 h = x;
173 x = realWidth - y;
174 y = h;
175 break;
176
177 case ORIENTATION_ROTATE90CCW:
178 h = x;
179 x = y;
180 y = realHeight - h;
181 break;
182 }
183 }
184
transformInverse(PPRect & r)185 void PPDisplayDevice::transformInverse(PPRect& r)
186 {
187 transformInverse((pp_int32&)r.x1, (pp_int32&)r.y1);
188 transformInverse((pp_int32&)r.x2, (pp_int32&)r.y2);
189
190 pp_int32 h;
191 if (r.x2 < r.x1)
192 {
193 h = r.x1; r.x1 = r.x2; r.x2 = h;
194 }
195 if (r.y2 < r.y1)
196 {
197 h = r.y1; r.y1 = r.y2; r.y2 = h;
198 }
199 }
200
setTitle(const PPSystemString & title)201 void PPDisplayDevice::setTitle(const PPSystemString& title)
202 {
203 SDL_SetWindowTitle(theWindow, title);
204 }
205
goFullScreen(bool b)206 bool PPDisplayDevice::goFullScreen(bool b)
207 {
208 // In X11, this will make MilkyTracker go fullscreen at the selected
209 // resolution.
210
211 if (!b && (SDL_SetWindowFullscreen(theWindow, SDL_FALSE) == 0))
212 {
213 bFullScreen = false;
214 return true;
215 }
216
217 else if (b && (SDL_SetWindowFullscreen(theWindow, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0))
218 {
219 bFullScreen = true;
220 return true;
221 }
222
223 return false;
224 }
225
getWindow()226 SDL_Window* PPDisplayDevice::getWindow() {
227 return theWindow;
228 }
229
230 // Defined in main.cpp
231 void exitSDLEventLoop(bool serializedEventInvoked = true);
232
getDisplayResolution() const233 PPSize PPDisplayDevice::getDisplayResolution() const {
234 // Find the monitor MilkyTracker is being displayed on
235 int currentDisplay = SDL_GetWindowDisplayIndex(theWindow);
236
237 // Structure to hold the display resolution
238 SDL_DisplayMode displayMode;
239
240 // If this fails, return -1 dimensions (makes MilkyTracker display an error)
241 if (SDL_GetDesktopDisplayMode(currentDisplay, &displayMode) != 0)
242 return PPSize(-1, -1);
243
244 // Return the desktop size
245 return PPSize(displayMode.w, displayMode.h);
246 }
247
shutDown()248 void PPDisplayDevice::shutDown()
249 {
250 exitSDLEventLoop();
251 }
252
setMouseCursor(MouseCursorTypes type)253 void PPDisplayDevice::setMouseCursor(MouseCursorTypes type)
254 {
255 currentCursorType = type;
256
257 switch (type)
258 {
259 case MouseCursorTypeStandard:
260 SDL_SetCursor(cursorStandard);
261 break;
262
263 case MouseCursorTypeResizeLeft:
264 case MouseCursorTypeResizeRight:
265 SDL_SetCursor(cursorResizeHoriz);
266 break;
267
268 case MouseCursorTypeHand:
269 SDL_SetCursor(cursorHand);
270 break;
271
272 case MouseCursorTypeWait:
273 SDL_SetCursor(cursorEggtimer);
274 break;
275 }
276 }
277
signalWaitState(bool b,const PPColor & color)278 void PPDisplayDevice::signalWaitState(bool b, const PPColor& color)
279 {
280 setMouseCursor(b ? MouseCursorTypeWait : MouseCursorTypeStandard);
281 }
282
initMousePointers()283 void PPDisplayDevice::initMousePointers()
284 {
285 cursorStandard = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
286 cursorResizeHoriz = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
287 cursorEggtimer = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
288 cursorHand = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
289 }
290