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