1 #pragma once
2
3 #include <SDL.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <math.h>
10 #include <cstddef>
11
12 #include "console.h"
13 #include "../SourceX/stubs.h"
14
15 #define WINDOW_ICON_NAME 0
16
17 //== Utility
18
19 #define SDL_zero(x) SDL_memset(&(x), 0, sizeof((x)))
20 #define SDL_InvalidParamError(param) SDL_SetError("Parameter '%s' is invalid", (param))
21 #define SDL_floor floor
22
23 #define SDL_MAX_UINT32 ((Uint32)0xFFFFFFFFu)
24
25 //== Events handling
26
27 #define SDL_threadID Uint32
28
29 #define SDL_Keysym SDL_keysym
30 #define SDL_Keycode SDLKey
31
32 #define SDLK_PRINTSCREEN SDLK_PRINT
33 #define SDLK_SCROLLLOCK SDLK_SCROLLOCK
34 #define SDLK_NUMLOCKCLEAR SDLK_NUMLOCK
35 #define SDLK_KP_1 SDLK_KP1
36 #define SDLK_KP_2 SDLK_KP2
37 #define SDLK_KP_3 SDLK_KP3
38 #define SDLK_KP_4 SDLK_KP4
39 #define SDLK_KP_5 SDLK_KP5
40 #define SDLK_KP_6 SDLK_KP6
41 #define SDLK_KP_7 SDLK_KP7
42 #define SDLK_KP_8 SDLK_KP8
43 #define SDLK_KP_9 SDLK_KP9
44 #define SDLK_KP_0 SDLK_KP0
45 #define SDLK_LGUI SDLK_LSUPER
46 #define SDLK_RGUI SDLK_RSUPER
47
48 // Haptic events are not supported in SDL1.
49 #define SDL_INIT_HAPTIC 0
50
51 // For now we only process ASCII input when using SDL1.
52 #define SDL_TEXTINPUTEVENT_TEXT_SIZE 2
53
54 #define SDL_JoystickID Sint32
55 #define SDL_JoystickNameForIndex SDL_JoystickName
56
SDL_Log(const char * fmt,...)57 inline void SDL_Log(const char *fmt, ...)
58 {
59 char message[256];
60 va_list ap;
61 va_start(ap, fmt);
62 vsprintf(message, fmt, ap);
63 va_end(ap);
64
65 printInConsole("INFO: %s\n", message);
66 }
67
SDL_StartTextInput()68 inline void SDL_StartTextInput()
69 {
70 }
71
SDL_StopTextInput()72 inline void SDL_StopTextInput()
73 {
74 }
75
SDL_SetTextInputRect(const SDL_Rect * r)76 inline void SDL_SetTextInputRect(const SDL_Rect *r)
77 {
78 }
79
80 //== Graphics helpers
81
82 typedef struct SDL_Point {
83 int x;
84 int y;
85 } SDL_Point;
86
SDL_PointInRect(const SDL_Point * p,const SDL_Rect * r)87 inline SDL_bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r)
88 {
89 return ((p->x >= r->x) && (p->x < (r->x + r->w)) && (p->y >= r->y) && (p->y < (r->y + r->h))) ? SDL_TRUE : SDL_FALSE;
90 }
91
SDL_DisableScreenSaver()92 inline void SDL_DisableScreenSaver()
93 {
94 DUMMY();
95 }
96
97 //= Messagebox (simply logged to stderr for now)
98
99 typedef enum {
100 SDL_MESSAGEBOX_ERROR = 0x00000010, /**< error dialog */
101 SDL_MESSAGEBOX_WARNING = 0x00000020, /**< warning dialog */
102 SDL_MESSAGEBOX_INFORMATION = 0x00000040 /**< informational dialog */
103 } SDL_MessageBoxFlags;
104
SDL_ShowSimpleMessageBox(Uint32 flags,const char * title,const char * message,SDL_Surface * window)105 inline int SDL_ShowSimpleMessageBox(Uint32 flags,
106 const char *title,
107 const char *message,
108 SDL_Surface *window)
109 {
110 SDL_Log("MSGBOX: %s\n%s", title, message);
111 return 0;
112 }
113
114 //= Window handling
115
116 #define SDL_Window SDL_Surface
117
SDL_GetWindowPosition(SDL_Window * window,int * x,int * y)118 inline void SDL_GetWindowPosition(SDL_Window *window, int *x, int *y)
119 {
120 *x = window->clip_rect.x;
121 *y = window->clip_rect.x;
122 SDL_Log("SDL_GetWindowPosition %d %d", *x, *y);
123 }
124
SDL_SetWindowPosition(SDL_Window * window,int x,int y)125 inline void SDL_SetWindowPosition(SDL_Window *window, int x, int y)
126 {
127 DUMMY();
128 }
129
SDL_GetWindowSize(SDL_Window * window,int * w,int * h)130 inline void SDL_GetWindowSize(SDL_Window *window, int *w, int *h)
131 {
132 *w = window->clip_rect.w;
133 *h = window->clip_rect.h;
134 SDL_Log("SDL_GetWindowSize %d %d", *w, *h);
135 }
136
SDL_ShowWindow(SDL_Window * window)137 inline void SDL_ShowWindow(SDL_Window *window)
138 {
139 DUMMY();
140 }
141
SDL_HideWindow(SDL_Window * window)142 inline void SDL_HideWindow(SDL_Window *window)
143 {
144 DUMMY();
145 }
146
SDL_RaiseWindow(SDL_Window * window)147 inline void SDL_RaiseWindow(SDL_Window *window)
148 {
149 DUMMY();
150 }
151
SDL_DestroyWindow(SDL_Window * window)152 inline void SDL_DestroyWindow(SDL_Window *window)
153 {
154 SDL_FreeSurface(window);
155 }
156
157 inline void
SDL_WarpMouseInWindow(SDL_Window * window,int x,int y)158 SDL_WarpMouseInWindow(SDL_Window *window, int x, int y)
159 {
160 SDL_WarpMouse(x, y);
161 }
162
163 //= Renderer stubs
164
165 #define SDL_Renderer void
166
SDL_DestroyRenderer(SDL_Renderer * renderer)167 inline void SDL_DestroyRenderer(SDL_Renderer *renderer)
168 {
169 if (renderer != NULL)
170 UNIMPLEMENTED();
171 }
172
173 //= Texture stubs
174
175 #define SDL_Texture void
176
SDL_DestroyTexture(SDL_Texture * texture)177 inline void SDL_DestroyTexture(SDL_Texture *texture)
178 {
179 if (texture != NULL)
180 UNIMPLEMENTED();
181 }
182
183 //= Palette handling
184
185 inline SDL_Palette *
SDL_AllocPalette(int ncolors)186 SDL_AllocPalette(int ncolors)
187 {
188 SDL_Palette *palette;
189
190 /* Input validation */
191 if (ncolors < 1) {
192 SDL_InvalidParamError("ncolors");
193 return NULL;
194 }
195
196 palette = (SDL_Palette *)SDL_malloc(sizeof(*palette));
197 if (!palette) {
198 SDL_OutOfMemory();
199 return NULL;
200 }
201 palette->colors = (SDL_Color *)SDL_malloc(ncolors * sizeof(*palette->colors));
202 if (!palette->colors) {
203 SDL_free(palette);
204 return NULL;
205 }
206 palette->ncolors = ncolors;
207 SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors));
208 return palette;
209 }
210
211 inline void
SDL_FreePalette(SDL_Palette * palette)212 SDL_FreePalette(SDL_Palette *palette)
213 {
214 if (!palette) {
215 SDL_InvalidParamError("palette");
216 return;
217 }
218 SDL_free(palette->colors);
219 SDL_free(palette);
220 }
221
SDL_HasColorKey(SDL_Surface * surface)222 inline bool SDL_HasColorKey(SDL_Surface *surface)
223 {
224 return (surface->flags & SDL_SRCCOLORKEY) != 0;
225 }
226
227 //= Pixel formats
228
229 #define SDL_PIXELFORMAT_INDEX8 1
230 #define SDL_PIXELFORMAT_RGB888 2
231 #define SDL_PIXELFORMAT_RGBA8888 3
232
SDLBackport_PixelformatToMask(int pixelformat,Uint32 * flags,Uint32 * rmask,Uint32 * gmask,Uint32 * bmask,Uint32 * amask)233 inline void SDLBackport_PixelformatToMask(int pixelformat, Uint32 *flags, Uint32 *rmask,
234 Uint32 *gmask,
235 Uint32 *bmask,
236 Uint32 *amask)
237 {
238 if (pixelformat == SDL_PIXELFORMAT_RGBA8888) {
239 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
240 *rmask = 0xff000000;
241 *gmask = 0x00ff0000;
242 *bmask = 0x0000ff00;
243 *amask = 0x000000ff;
244 #else
245 *rmask = 0x000000ff;
246 *gmask = 0x0000ff00;
247 *bmask = 0x00ff0000;
248 *amask = 0xff000000;
249 #endif
250 } else if (pixelformat == SDL_PIXELFORMAT_RGB888) {
251 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
252 *rmask = 0xff000000;
253 *gmask = 0x00ff0000;
254 *bmask = 0x0000ff00;
255 #else
256 *rmask = 0x000000ff;
257 *gmask = 0x0000ff00;
258 *bmask = 0x00ff0000;
259 #endif
260 *amask = 0;
261 } else {
262 *rmask = *gmask = *bmask = *amask = 0;
263 }
264 }
265
266 /**
267 * A limited implementation of `a.format` == `b.format` from SDL2.
268 */
SDLBackport_PixelFormatFormatEq(const SDL_PixelFormat * a,const SDL_PixelFormat * b)269 inline bool SDLBackport_PixelFormatFormatEq(const SDL_PixelFormat *a, const SDL_PixelFormat *b)
270 {
271 return a->BitsPerPixel == b->BitsPerPixel && (a->palette != NULL) == (b->palette != NULL)
272 && a->Rmask == b->Rmask && a->Gmask == b->Gmask && a->Bmask == b->Bmask;
273 }
274
275 /**
276 * Similar to `SDL_ISPIXELFORMAT_INDEXED` from SDL2.
277 */
SDLBackport_IsPixelFormatIndexed(const SDL_PixelFormat * pf)278 inline bool SDLBackport_IsPixelFormatIndexed(const SDL_PixelFormat *pf)
279 {
280 return pf->BitsPerPixel == 8 && pf->palette != NULL;
281 }
282
283 //= Surface creation
284
285 inline SDL_Surface *
SDL_CreateRGBSurfaceWithFormat(Uint32 flags,int width,int height,int depth,Uint32 format)286 SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
287 Uint32 format)
288 {
289 Uint32 rmask, gmask, bmask, amask;
290 SDLBackport_PixelformatToMask(format, &flags, &rmask, &gmask, &bmask, &amask);
291 return SDL_CreateRGBSurface(flags, width, height, depth, rmask, gmask, bmask, amask);
292 }
293
294 inline SDL_Surface *
SDL_CreateRGBSurfaceWithFormatFrom(void * pixels,Uint32 flags,int width,int height,int depth,Uint32 format)295 SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, Uint32 flags, int width, int height, int depth,
296 Uint32 format)
297 {
298 Uint32 rmask, gmask, bmask, amask;
299 SDLBackport_PixelformatToMask(format, &flags, &rmask, &gmask, &bmask, &amask);
300 return SDL_CreateRGBSurfaceFrom(pixels, flags, width, height, depth, rmask, gmask, bmask, amask);
301 }
302
303 //= BlitScaled backport from SDL 2.0.9.
304
305 #define SDL_BlitScaled SDL_UpperBlitScaled
306
307 #define DEFINE_COPY_ROW(name, type) \
308 static void name(type *src, int src_w, type *dst, int dst_w) \
309 { \
310 int i; \
311 int pos, inc; \
312 type pixel = 0; \
313 \
314 pos = 0x10000; \
315 inc = (src_w << 16) / dst_w; \
316 for (i = dst_w; i > 0; --i) { \
317 while (pos >= 0x10000L) { \
318 pixel = *src++; \
319 pos -= 0x10000L; \
320 } \
321 *dst++ = pixel; \
322 pos += inc; \
323 } \
324 }
DEFINE_COPY_ROW(copy_row1,Uint8)325 DEFINE_COPY_ROW(copy_row1, Uint8)
326 DEFINE_COPY_ROW(copy_row2, Uint16)
327 DEFINE_COPY_ROW(copy_row4, Uint32)
328
329 static void
330 copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
331 {
332 int i;
333 int pos, inc;
334 Uint8 pixel[3] = { 0, 0, 0 };
335
336 pos = 0x10000;
337 inc = (src_w << 16) / dst_w;
338 for (i = dst_w; i > 0; --i) {
339 while (pos >= 0x10000L) {
340 pixel[0] = *src++;
341 pixel[1] = *src++;
342 pixel[2] = *src++;
343 pos -= 0x10000L;
344 }
345 *dst++ = pixel[0];
346 *dst++ = pixel[1];
347 *dst++ = pixel[2];
348 pos += inc;
349 }
350 }
351
352 // NOTE: Not thread-safe
353 inline int
SDL_SoftStretch(SDL_Surface * src,const SDL_Rect * srcrect,SDL_Surface * dst,const SDL_Rect * dstrect)354 SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
355 SDL_Surface *dst, const SDL_Rect *dstrect)
356 {
357 // All the ASM support has been removed, as the platforms that the ASM
358 // implementation exists for support SDL2 anyway.
359 int src_locked;
360 int dst_locked;
361 int pos, inc;
362 int dst_maxrow;
363 int src_row, dst_row;
364 Uint8 *srcp = NULL;
365 Uint8 *dstp;
366 SDL_Rect full_src;
367 SDL_Rect full_dst;
368 const int bpp = dst->format->BytesPerPixel;
369
370 if (!SDLBackport_PixelFormatFormatEq(src->format, dst->format)) {
371 SDL_SetError("Only works with same format surfaces");
372 return -1;
373 }
374
375 /* Verify the blit rectangles */
376 if (srcrect) {
377 if ((srcrect->x < 0) || (srcrect->y < 0) || ((srcrect->x + srcrect->w) > src->w) || ((srcrect->y + srcrect->h) > src->h)) {
378 SDL_SetError("Invalid source blit rectangle");
379 return -1;
380 }
381 } else {
382 full_src.x = 0;
383 full_src.y = 0;
384 full_src.w = src->w;
385 full_src.h = src->h;
386 srcrect = &full_src;
387 }
388 if (dstrect) {
389 if ((dstrect->x < 0) || (dstrect->y < 0) || ((dstrect->x + dstrect->w) > dst->w) || ((dstrect->y + dstrect->h) > dst->h)) {
390 SDL_SetError("Invalid destination blit rectangle");
391 return -1;
392 }
393 } else {
394 full_dst.x = 0;
395 full_dst.y = 0;
396 full_dst.w = dst->w;
397 full_dst.h = dst->h;
398 dstrect = &full_dst;
399 }
400
401 /* Lock the destination if it's in hardware */
402 dst_locked = 0;
403 if (SDL_MUSTLOCK(dst)) {
404 if (SDL_LockSurface(dst) < 0) {
405 SDL_SetError("Unable to lock destination surface");
406 return -1;
407 }
408 dst_locked = 1;
409 }
410 /* Lock the source if it's in hardware */
411 src_locked = 0;
412 if (SDL_MUSTLOCK(src)) {
413 if (SDL_LockSurface(src) < 0) {
414 if (dst_locked) {
415 SDL_UnlockSurface(dst);
416 }
417 SDL_SetError("Unable to lock source surface");
418 return -1;
419 }
420 src_locked = 1;
421 }
422
423 /* Set up the data... */
424 pos = 0x10000;
425 inc = (srcrect->h << 16) / dstrect->h;
426 src_row = srcrect->y;
427 dst_row = dstrect->y;
428
429 /* Perform the stretch blit */
430 for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
431 dstp = (Uint8 *)dst->pixels + (dst_row * dst->pitch)
432 + (dstrect->x * bpp);
433 while (pos >= 0x10000L) {
434 srcp = (Uint8 *)src->pixels + (src_row * src->pitch)
435 + (srcrect->x * bpp);
436 ++src_row;
437 pos -= 0x10000L;
438 }
439 switch (bpp) {
440 case 1:
441 copy_row1(srcp, srcrect->w, dstp, dstrect->w);
442 break;
443 case 2:
444 copy_row2((Uint16 *)srcp, srcrect->w,
445 (Uint16 *)dstp, dstrect->w);
446 break;
447 case 3:
448 copy_row3(srcp, srcrect->w, dstp, dstrect->w);
449 break;
450 case 4:
451 copy_row4((Uint32 *)srcp, srcrect->w,
452 (Uint32 *)dstp, dstrect->w);
453 break;
454 }
455 pos += inc;
456 }
457
458 /* We need to unlock the surfaces if they're locked */
459 if (dst_locked) {
460 SDL_UnlockSurface(dst);
461 }
462 if (src_locked) {
463 SDL_UnlockSurface(src);
464 }
465 return (0);
466 }
467
468 inline int
SDL_LowerBlitScaled(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)469 SDL_LowerBlitScaled(SDL_Surface *src, SDL_Rect *srcrect,
470 SDL_Surface *dst, SDL_Rect *dstrect)
471 {
472 if (SDLBackport_PixelFormatFormatEq(src->format, dst->format) && !SDLBackport_IsPixelFormatIndexed(src->format)) {
473 return SDL_SoftStretch(src, srcrect, dst, dstrect);
474 } else {
475 return SDL_LowerBlit(src, srcrect, dst, dstrect);
476 }
477 }
478
479 // NOTE: The second argument is const in SDL2 but not here.
480 inline int
SDL_UpperBlitScaled(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)481 SDL_UpperBlitScaled(SDL_Surface *src, SDL_Rect *srcrect,
482 SDL_Surface *dst, SDL_Rect *dstrect)
483 {
484 double src_x0, src_y0, src_x1, src_y1;
485 double dst_x0, dst_y0, dst_x1, dst_y1;
486 SDL_Rect final_src, final_dst;
487 double scaling_w, scaling_h;
488 int src_w, src_h;
489 int dst_w, dst_h;
490
491 /* Make sure the surfaces aren't locked */
492 if (!src || !dst) {
493 SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
494 return -1;
495 }
496 if (src->locked || dst->locked) {
497 SDL_SetError("Surfaces must not be locked during blit");
498 return -1;
499 }
500
501 if (NULL == srcrect) {
502 src_w = src->w;
503 src_h = src->h;
504 } else {
505 src_w = srcrect->w;
506 src_h = srcrect->h;
507 }
508
509 if (NULL == dstrect) {
510 dst_w = dst->w;
511 dst_h = dst->h;
512 } else {
513 dst_w = dstrect->w;
514 dst_h = dstrect->h;
515 }
516
517 if (dst_w == src_w && dst_h == src_h) {
518 /* No scaling, defer to regular blit */
519 return SDL_BlitSurface(src, srcrect, dst, dstrect);
520 }
521
522 scaling_w = (double)dst_w / src_w;
523 scaling_h = (double)dst_h / src_h;
524
525 if (NULL == dstrect) {
526 dst_x0 = 0;
527 dst_y0 = 0;
528 dst_x1 = dst_w - 1;
529 dst_y1 = dst_h - 1;
530 } else {
531 dst_x0 = dstrect->x;
532 dst_y0 = dstrect->y;
533 dst_x1 = dst_x0 + dst_w - 1;
534 dst_y1 = dst_y0 + dst_h - 1;
535 }
536
537 if (NULL == srcrect) {
538 src_x0 = 0;
539 src_y0 = 0;
540 src_x1 = src_w - 1;
541 src_y1 = src_h - 1;
542 } else {
543 src_x0 = srcrect->x;
544 src_y0 = srcrect->y;
545 src_x1 = src_x0 + src_w - 1;
546 src_y1 = src_y0 + src_h - 1;
547
548 /* Clip source rectangle to the source surface */
549
550 if (src_x0 < 0) {
551 dst_x0 -= src_x0 * scaling_w;
552 src_x0 = 0;
553 }
554
555 if (src_x1 >= src->w) {
556 dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
557 src_x1 = src->w - 1;
558 }
559
560 if (src_y0 < 0) {
561 dst_y0 -= src_y0 * scaling_h;
562 src_y0 = 0;
563 }
564
565 if (src_y1 >= src->h) {
566 dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
567 src_y1 = src->h - 1;
568 }
569 }
570
571 /* Clip destination rectangle to the clip rectangle */
572
573 /* Translate to clip space for easier calculations */
574 dst_x0 -= dst->clip_rect.x;
575 dst_x1 -= dst->clip_rect.x;
576 dst_y0 -= dst->clip_rect.y;
577 dst_y1 -= dst->clip_rect.y;
578
579 if (dst_x0 < 0) {
580 src_x0 -= dst_x0 / scaling_w;
581 dst_x0 = 0;
582 }
583
584 if (dst_x1 >= dst->clip_rect.w) {
585 src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
586 dst_x1 = dst->clip_rect.w - 1;
587 }
588
589 if (dst_y0 < 0) {
590 src_y0 -= dst_y0 / scaling_h;
591 dst_y0 = 0;
592 }
593
594 if (dst_y1 >= dst->clip_rect.h) {
595 src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
596 dst_y1 = dst->clip_rect.h - 1;
597 }
598
599 /* Translate back to surface coordinates */
600 dst_x0 += dst->clip_rect.x;
601 dst_x1 += dst->clip_rect.x;
602 dst_y0 += dst->clip_rect.y;
603 dst_y1 += dst->clip_rect.y;
604
605 final_src.x = (Sint16)SDL_floor(src_x0 + 0.5);
606 final_src.y = (Sint16)SDL_floor(src_y0 + 0.5);
607 src_w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
608 src_h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
609 if (src_w < 0)
610 src_w = 0;
611 if (src_h < 0)
612 src_h = 0;
613
614 final_src.w = static_cast<Uint16>(src_w);
615 final_src.h = static_cast<Uint16>(src_h);
616
617 final_dst.x = (Sint16)SDL_floor(dst_x0 + 0.5);
618 final_dst.y = (Sint16)SDL_floor(dst_y0 + 0.5);
619 dst_w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
620 dst_h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
621 if (dst_w < 0)
622 dst_w = 0;
623 if (dst_h < 0)
624 dst_h = 0;
625
626 final_dst.w = static_cast<Uint16>(dst_w);
627 final_dst.h = static_cast<Uint16>(dst_h);
628
629 if (dstrect)
630 *dstrect = final_dst;
631
632 if (final_dst.w == 0 || final_dst.h == 0 || final_src.w == 0 || final_src.h == 0) {
633 /* No-op. */
634 return 0;
635 }
636
637 return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
638 }
639
640 //= Display handling
641
642 typedef struct
643 {
644 Uint32 format; /**< pixel format */
645 int w; /**< width, in screen coordinates */
646 int h; /**< height, in screen coordinates */
647 int refresh_rate; /**< refresh rate (or zero for unspecified) */
648 void *driverdata; /**< driver-specific data, initialize to 0 */
649 } SDL_DisplayMode;
650
SDL_GetCurrentDisplayMode(int displayIndex,SDL_DisplayMode * mode)651 inline int SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode *mode)
652 {
653 if (displayIndex != 0)
654 UNIMPLEMENTED();
655
656 const SDL_VideoInfo *info = SDL_GetVideoInfo();
657 if (info == NULL)
658 return 0;
659
660 switch (info->vfmt->BitsPerPixel) {
661 case 8:
662 mode->format = SDL_PIXELFORMAT_INDEX8;
663 break;
664 case 24:
665 mode->format = SDL_PIXELFORMAT_RGB888;
666 break;
667 case 32:
668 mode->format = SDL_PIXELFORMAT_RGBA8888;
669 break;
670 default:
671 mode->format = 0;
672 break;
673 }
674
675 mode->w = info->current_w;
676 mode->h = info->current_h;
677 mode->refresh_rate = 0;
678 mode->driverdata = NULL;
679
680 return 0;
681 }
682
683 //== Filesystem
684
685 #if !defined(__QNXNTO__)
686 inline char *
readSymLink(const char * path)687 readSymLink(const char *path)
688 {
689 // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c
690 char *retval = NULL;
691 ssize_t len = 64;
692 ssize_t rc = -1;
693
694 while (1) {
695 char *ptr = (char *)SDL_realloc(retval, (size_t)len);
696 if (ptr == NULL) {
697 SDL_OutOfMemory();
698 break;
699 }
700
701 retval = ptr;
702
703 rc = readlink(path, retval, len);
704 if (rc == -1) {
705 break; /* not a symlink, i/o error, etc. */
706 } else if (rc < len) {
707 retval[rc] = '\0'; /* readlink doesn't null-terminate. */
708 return retval; /* we're good to go. */
709 }
710
711 len *= 2; /* grow buffer, try again. */
712 }
713
714 SDL_free(retval);
715 return NULL;
716 }
717 #endif
718
SDL_GetBasePath()719 inline char *SDL_GetBasePath()
720 {
721 // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c
722
723 char *retval = NULL;
724
725 #if defined(__FREEBSD__)
726 char fullpath[PATH_MAX];
727 size_t buflen = sizeof(fullpath);
728 const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
729 if (sysctl(mib, SDL_arraysize(mib), fullpath, &buflen, NULL, 0) != -1) {
730 retval = SDL_strdup(fullpath);
731 if (!retval) {
732 SDL_OutOfMemory();
733 return NULL;
734 }
735 }
736 #endif
737 #if defined(__OPENBSD__)
738 char **retvalargs;
739 size_t len;
740 const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
741 if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) {
742 retvalargs = SDL_malloc(len);
743 if (!retvalargs) {
744 SDL_OutOfMemory();
745 return NULL;
746 }
747 sysctl(mib, 4, retvalargs, &len, NULL, 0);
748 retval = SDL_malloc(PATH_MAX + 1);
749 if (retval)
750 realpath(retvalargs[0], retval);
751
752 SDL_free(retvalargs);
753 }
754 #endif
755 #if defined(__SOLARIS__)
756 const char *path = getexecname();
757 if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */
758 retval = SDL_strdup(path);
759 if (!retval) {
760 SDL_OutOfMemory();
761 return NULL;
762 }
763 }
764 #endif
765 #if defined(__3DS__)
766 retval = SDL_strdup("file:sdmc:/3ds/devilutionx/");
767 return retval;
768 #endif
769
770 /* is a Linux-style /proc filesystem available? */
771 if (!retval && (access("/proc", F_OK) == 0)) {
772 /* !!! FIXME: after 2.0.6 ships, let's delete this code and just
773 use the /proc/%llu version. There's no reason to have
774 two copies of this plus all the #ifdefs. --ryan. */
775 #if defined(__FREEBSD__)
776 retval = readSymLink("/proc/curproc/file");
777 #elif defined(__NETBSD__)
778 retval = readSymLink("/proc/curproc/exe");
779 #elif defined(__QNXNTO__)
780 retval = SDL_LoadFile("/proc/self/exefile", NULL);
781 #else
782 retval = readSymLink("/proc/self/exe"); /* linux. */
783 if (retval == NULL) {
784 /* older kernels don't have /proc/self ... try PID version... */
785 char path[64];
786 const int rc = (int)SDL_snprintf(path, sizeof(path),
787 "/proc/%llu/exe",
788 (unsigned long long)getpid());
789 if ((rc > 0) && (static_cast<std::size_t>(rc) < sizeof(path))) {
790 retval = readSymLink(path);
791 }
792 }
793 #endif
794 }
795
796 /* If we had access to argv[0] here, we could check it for a path,
797 or troll through $PATH looking for it, too. */
798
799 if (retval != NULL) { /* chop off filename. */
800 char *ptr = SDL_strrchr(retval, '/');
801 if (ptr != NULL) {
802 *(ptr + 1) = '\0';
803 } else { /* shouldn't happen, but just in case... */
804 SDL_free(retval);
805 retval = NULL;
806 }
807 }
808
809 if (retval != NULL) {
810 /* try to shrink buffer... */
811 char *ptr = (char *)SDL_realloc(retval, strlen(retval) + 1);
812 if (ptr != NULL)
813 retval = ptr; /* oh well if it failed. */
814 }
815
816 return retval;
817 }
818
SDL_GetPrefPath(const char * org,const char * app)819 inline char *SDL_GetPrefPath(const char *org, const char *app)
820 {
821 // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c
822 /*
823 * We use XDG's base directory spec, even if you're not on Linux.
824 * This isn't strictly correct, but the results are relatively sane
825 * in any case.
826 *
827 * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
828 */
829 const char *envr = SDL_getenv("XDG_DATA_HOME");
830 const char *append;
831 char *retval = NULL;
832 char *ptr = NULL;
833 size_t len = 0;
834
835 #if defined(__3DS__)
836 retval = SDL_strdup("sdmc:/3ds/devilutionx/");
837 return retval;
838 #endif
839
840 if (!app) {
841 SDL_InvalidParamError("app");
842 return NULL;
843 }
844 if (!org) {
845 org = "";
846 }
847
848 if (!envr) {
849 /* You end up with "$HOME/.local/share/Game Name 2" */
850 envr = SDL_getenv("HOME");
851 if (!envr) {
852 /* we could take heroic measures with /etc/passwd, but oh well. */
853 SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set");
854 return NULL;
855 }
856 #if defined(__unix__) || defined(__unix)
857 append = "/.local/share/";
858 #else
859 append = "/";
860 #endif
861 } else {
862 append = "/";
863 }
864
865 len = SDL_strlen(envr);
866 if (envr[len - 1] == '/')
867 append += 1;
868
869 len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3;
870 retval = (char *)SDL_malloc(len);
871 if (!retval) {
872 SDL_OutOfMemory();
873 return NULL;
874 }
875
876 if (*org) {
877 SDL_snprintf(retval, len, "%s%s%s/%s", envr, append, org, app);
878 } else {
879 SDL_snprintf(retval, len, "%s%s%s", envr, append, app);
880 }
881
882 for (ptr = retval + 1; *ptr; ptr++) {
883 if (*ptr == '/') {
884 *ptr = '\0';
885 if (mkdir(retval, 0700) != 0 && errno != EEXIST)
886 goto error;
887 *ptr = '/';
888 }
889 }
890 if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
891 error:
892 SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno));
893 SDL_free(retval);
894 return NULL;
895 }
896
897 // Append trailing /
898 size_t final_len = SDL_strlen(retval);
899 if (final_len + 1 < len) {
900 retval[final_len++] = '/';
901 retval[final_len] = '\0';
902 }
903
904 return retval;
905 }
906