1 
2 // HEADER FILES ------------------------------------------------------------
3 
4 #include "doomtype.h"
5 
6 #include "templates.h"
7 #include "i_system.h"
8 #include "i_video.h"
9 #include "v_video.h"
10 #include "v_pfx.h"
11 #include "stats.h"
12 #include "v_palette.h"
13 #include "sdlvideo.h"
14 #include "r_swrenderer.h"
15 #include "version.h"
16 
17 #include <SDL.h>
18 
19 #ifdef __APPLE__
20 #include <OpenGL/OpenGL.h>
21 #endif // __APPLE__
22 
23 // MACROS ------------------------------------------------------------------
24 
25 // TYPES -------------------------------------------------------------------
26 
27 class SDLFB : public DFrameBuffer
28 {
29 	DECLARE_CLASS(SDLFB, DFrameBuffer)
30 public:
31 	SDLFB (int width, int height, bool fullscreen, SDL_Window *oldwin);
32 	~SDLFB ();
33 
34 	bool Lock (bool buffer);
35 	void Unlock ();
36 	bool Relock ();
37 	void ForceBuffering (bool force);
38 	bool IsValid ();
39 	void Update ();
40 	PalEntry *GetPalette ();
41 	void GetFlashedPalette (PalEntry pal[256]);
42 	void UpdatePalette ();
43 	bool SetGamma (float gamma);
44 	bool SetFlash (PalEntry rgb, int amount);
45 	void GetFlash (PalEntry &rgb, int &amount);
46 	void SetFullscreen (bool fullscreen);
47 	int GetPageCount ();
48 	bool IsFullscreen ();
49 
50 	friend class SDLVideo;
51 
52 	virtual void SetVSync (bool vsync);
53 	virtual void ScaleCoordsFromWindow(SWORD &x, SWORD &y);
54 
55 private:
56 	PalEntry SourcePalette[256];
57 	BYTE GammaTable[3][256];
58 	PalEntry Flash;
59 	int FlashAmount;
60 	float Gamma;
61 	bool UpdatePending;
62 
63 	SDL_Window *Screen;
64 	SDL_Renderer *Renderer;
65 	union
66 	{
67 		SDL_Texture *Texture;
68 		SDL_Surface *Surface;
69 	};
70 
71 	bool UsingRenderer;
72 	bool NeedPalUpdate;
73 	bool NeedGammaUpdate;
74 	bool NotPaletted;
75 
76 	void UpdateColors ();
77 	void ResetSDLRenderer ();
78 
SDLFB()79 	SDLFB () {}
80 };
81 IMPLEMENT_CLASS(SDLFB)
82 
83 struct MiniModeInfo
84 {
85 	WORD Width, Height;
86 };
87 
88 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
89 
90 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
91 
92 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
93 
94 extern IVideo *Video;
95 extern bool GUICapture;
96 
EXTERN_CVAR(Float,Gamma)97 EXTERN_CVAR (Float, Gamma)
98 EXTERN_CVAR (Int, vid_maxfps)
99 EXTERN_CVAR (Bool, cl_capfps)
100 EXTERN_CVAR (Bool, vid_vsync)
101 
102 // PUBLIC DATA DEFINITIONS -------------------------------------------------
103 
104 CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
105 
106 CVAR (Int, vid_displaybits, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
107 
108 CVAR (Bool, vid_forcesurface, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
109 
110 CUSTOM_CVAR (Float, rgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
111 {
112 	if (screen != NULL)
113 	{
114 		screen->SetGamma (Gamma);
115 	}
116 }
117 CUSTOM_CVAR (Float, ggamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
118 {
119 	if (screen != NULL)
120 	{
121 		screen->SetGamma (Gamma);
122 	}
123 }
124 CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
125 {
126 	if (screen != NULL)
127 	{
128 		screen->SetGamma (Gamma);
129 	}
130 }
131 
132 // PRIVATE DATA DEFINITIONS ------------------------------------------------
133 
134 // Dummy screen sizes to pass when windowed
135 static MiniModeInfo WinModes[] =
136 {
137 	{ 320, 200 },
138 	{ 320, 240 },
139 	{ 400, 225 },	// 16:9
140 	{ 400, 300 },
141 	{ 480, 270 },	// 16:9
142 	{ 480, 360 },
143 	{ 512, 288 },	// 16:9
144 	{ 512, 384 },
145 	{ 640, 360 },	// 16:9
146 	{ 640, 400 },
147 	{ 640, 480 },
148 	{ 720, 480 },	// 16:10
149 	{ 720, 540 },
150 	{ 800, 450 },	// 16:9
151 	{ 800, 480 },
152 	{ 800, 500 },	// 16:10
153 	{ 800, 600 },
154 	{ 848, 480 },	// 16:9
155 	{ 960, 600 },	// 16:10
156 	{ 960, 720 },
157 	{ 1024, 576 },	// 16:9
158 	{ 1024, 600 },	// 17:10
159 	{ 1024, 640 },	// 16:10
160 	{ 1024, 768 },
161 	{ 1088, 612 },	// 16:9
162 	{ 1152, 648 },	// 16:9
163 	{ 1152, 720 },	// 16:10
164 	{ 1152, 864 },
165 	{ 1280, 720 },	// 16:9
166 	{ 1280, 854 },
167 	{ 1280, 800 },	// 16:10
168 	{ 1280, 960 },
169 	{ 1280, 1024 },	// 5:4
170 	{ 1360, 768 },	// 16:9
171 	{ 1366, 768 },
172 	{ 1400, 787 },	// 16:9
173 	{ 1400, 875 },	// 16:10
174 	{ 1400, 1050 },
175 	{ 1440, 900 },
176 	{ 1440, 960 },
177 	{ 1440, 1080 },
178 	{ 1600, 900 },	// 16:9
179 	{ 1600, 1000 },	// 16:10
180 	{ 1600, 1200 },
181 	{ 1680, 1050 },	// 16:10
182 	{ 1920, 1080 },
183 	{ 1920, 1200 },
184 	{ 2048, 1536 },
185 	{ 2560, 1440 },
186 	{ 2560, 1600 },
187 	{ 2560, 2048 },
188 	{ 2880, 1800 },
189 	{ 3200, 1800 },
190 	{ 3840, 2160 },
191 	{ 3840, 2400 },
192 	{ 4096, 2160 },
193 	{ 5120, 2880 }
194 };
195 
196 static cycle_t BlitCycles;
197 static cycle_t SDLFlipCycles;
198 
199 // CODE --------------------------------------------------------------------
200 
ScaleWithAspect(int & w,int & h,int Width,int Height)201 void ScaleWithAspect (int &w, int &h, int Width, int Height)
202 {
203 	int resRatio = CheckRatio (Width, Height);
204 	int screenRatio;
205 	CheckRatio (w, h, &screenRatio);
206 	if (resRatio == screenRatio)
207 		return;
208 
209 	double yratio;
210 	switch(resRatio)
211 	{
212 		case 0: yratio = 4./3.; break;
213 		case 1: yratio = 16./9.; break;
214 		case 2: yratio = 16./10.; break;
215 		case 3: yratio = 17./10.; break;
216 		case 4: yratio = 5./4.; break;
217 		default: return;
218 	}
219 	double y = w/yratio;
220 	if (y > h)
221 		w = h*yratio;
222 	else
223 		h = y;
224 }
225 
SDLVideo(int parm)226 SDLVideo::SDLVideo (int parm)
227 {
228 	IteratorBits = 0;
229 }
230 
~SDLVideo()231 SDLVideo::~SDLVideo ()
232 {
233 }
234 
StartModeIterator(int bits,bool fs)235 void SDLVideo::StartModeIterator (int bits, bool fs)
236 {
237 	IteratorMode = 0;
238 	IteratorBits = bits;
239 }
240 
NextMode(int * width,int * height,bool * letterbox)241 bool SDLVideo::NextMode (int *width, int *height, bool *letterbox)
242 {
243 	if (IteratorBits != 8)
244 		return false;
245 
246 	if ((unsigned)IteratorMode < sizeof(WinModes)/sizeof(WinModes[0]))
247 	{
248 		*width = WinModes[IteratorMode].Width;
249 		*height = WinModes[IteratorMode].Height;
250 		++IteratorMode;
251 		return true;
252 	}
253 	return false;
254 }
255 
CreateFrameBuffer(int width,int height,bool fullscreen,DFrameBuffer * old)256 DFrameBuffer *SDLVideo::CreateFrameBuffer (int width, int height, bool fullscreen, DFrameBuffer *old)
257 {
258 	static int retry = 0;
259 	static int owidth, oheight;
260 
261 	PalEntry flashColor;
262 	int flashAmount;
263 
264 	SDL_Window *oldwin = NULL;
265 
266 	if (old != NULL)
267 	{ // Reuse the old framebuffer if its attributes are the same
268 		SDLFB *fb = static_cast<SDLFB *> (old);
269 		if (fb->Width == width &&
270 			fb->Height == height)
271 		{
272 			bool fsnow = (SDL_GetWindowFlags (fb->Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
273 
274 			if (fsnow != fullscreen)
275 			{
276 				fb->SetFullscreen (fullscreen);
277 			}
278 			return old;
279 		}
280 
281 		oldwin = fb->Screen;
282 		fb->Screen = NULL;
283 
284 		old->GetFlash (flashColor, flashAmount);
285 		old->ObjectFlags |= OF_YesReallyDelete;
286 		if (screen == old) screen = NULL;
287 		delete old;
288 	}
289 	else
290 	{
291 		flashColor = 0;
292 		flashAmount = 0;
293 	}
294 
295 	SDLFB *fb = new SDLFB (width, height, fullscreen, oldwin);
296 
297 	// If we could not create the framebuffer, try again with slightly
298 	// different parameters in this order:
299 	// 1. Try with the closest size
300 	// 2. Try in the opposite screen mode with the original size
301 	// 3. Try in the opposite screen mode with the closest size
302 	// This is a somewhat confusing mass of recursion here.
303 
304 	while (fb == NULL || !fb->IsValid ())
305 	{
306 		if (fb != NULL)
307 		{
308 			delete fb;
309 		}
310 
311 		switch (retry)
312 		{
313 		case 0:
314 			owidth = width;
315 			oheight = height;
316 		case 2:
317 			// Try a different resolution. Hopefully that will work.
318 			I_ClosestResolution (&width, &height, 8);
319 			break;
320 
321 		case 1:
322 			// Try changing fullscreen mode. Maybe that will work.
323 			width = owidth;
324 			height = oheight;
325 			fullscreen = !fullscreen;
326 			break;
327 
328 		default:
329 			// I give up!
330 			I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight);
331 		}
332 
333 		++retry;
334 		fb = static_cast<SDLFB *>(CreateFrameBuffer (width, height, fullscreen, NULL));
335 	}
336 	retry = 0;
337 
338 	fb->SetFlash (flashColor, flashAmount);
339 
340 	return fb;
341 }
342 
SetWindowedScale(float scale)343 void SDLVideo::SetWindowedScale (float scale)
344 {
345 }
346 
347 // FrameBuffer implementation -----------------------------------------------
348 
SDLFB(int width,int height,bool fullscreen,SDL_Window * oldwin)349 SDLFB::SDLFB (int width, int height, bool fullscreen, SDL_Window *oldwin)
350 	: DFrameBuffer (width, height)
351 {
352 	int i;
353 
354 	NeedPalUpdate = false;
355 	NeedGammaUpdate = false;
356 	UpdatePending = false;
357 	NotPaletted = false;
358 	FlashAmount = 0;
359 
360 	if (oldwin)
361 	{
362 		// In some cases (Mac OS X fullscreen) SDL2 doesn't like having multiple windows which
363 		// appears to inevitably happen while compositor animations are running. So lets try
364 		// to reuse the existing window.
365 		Screen = oldwin;
366 		SDL_SetWindowSize (Screen, width, height);
367 		SetFullscreen (fullscreen);
368 	}
369 	else
370 	{
371 		FString caption;
372 		caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
373 
374 		Screen = SDL_CreateWindow (caption,
375 			SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter), SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
376 			width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_RESIZABLE);
377 
378 		if (Screen == NULL)
379 			return;
380 	}
381 
382 	Renderer = NULL;
383 	Texture = NULL;
384 	ResetSDLRenderer ();
385 
386 	for (i = 0; i < 256; i++)
387 	{
388 		GammaTable[0][i] = GammaTable[1][i] = GammaTable[2][i] = i;
389 	}
390 
391 	memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
392 	UpdateColors ();
393 
394 #ifdef __APPLE__
395 	SetVSync (vid_vsync);
396 #endif
397 }
398 
399 
~SDLFB()400 SDLFB::~SDLFB ()
401 {
402 	if (Renderer)
403 	{
404 		if (Texture)
405 			SDL_DestroyTexture (Texture);
406 		SDL_DestroyRenderer (Renderer);
407 	}
408 
409 	if(Screen)
410 	{
411 		SDL_DestroyWindow (Screen);
412 	}
413 }
414 
IsValid()415 bool SDLFB::IsValid ()
416 {
417 	return DFrameBuffer::IsValid() && Screen != NULL;
418 }
419 
GetPageCount()420 int SDLFB::GetPageCount ()
421 {
422 	return 1;
423 }
424 
Lock(bool buffered)425 bool SDLFB::Lock (bool buffered)
426 {
427 	return DSimpleCanvas::Lock ();
428 }
429 
Relock()430 bool SDLFB::Relock ()
431 {
432 	return DSimpleCanvas::Lock ();
433 }
434 
Unlock()435 void SDLFB::Unlock ()
436 {
437 	if (UpdatePending && LockCount == 1)
438 	{
439 		Update ();
440 	}
441 	else if (--LockCount <= 0)
442 	{
443 		Buffer = NULL;
444 		LockCount = 0;
445 	}
446 }
447 
Update()448 void SDLFB::Update ()
449 {
450 	if (LockCount != 1)
451 	{
452 		if (LockCount > 0)
453 		{
454 			UpdatePending = true;
455 			--LockCount;
456 		}
457 		return;
458 	}
459 
460 	DrawRateStuff ();
461 
462 #if !defined(__APPLE__) && !defined(__DragonFly__)
463 	if(vid_maxfps && !cl_capfps)
464 	{
465 		SEMAPHORE_WAIT(FPSLimitSemaphore)
466 	}
467 #endif
468 
469 	Buffer = NULL;
470 	LockCount = 0;
471 	UpdatePending = false;
472 
473 	BlitCycles.Reset();
474 	SDLFlipCycles.Reset();
475 	BlitCycles.Clock();
476 
477 	void *pixels;
478 	int pitch;
479 	if (UsingRenderer)
480 	{
481 		if (SDL_LockTexture (Texture, NULL, &pixels, &pitch))
482 			return;
483 	}
484 	else
485 	{
486 		if (SDL_LockSurface (Surface))
487 			return;
488 
489 		pixels = Surface->pixels;
490 		pitch = Surface->pitch;
491 	}
492 
493 	if (NotPaletted)
494 	{
495 		GPfx.Convert (MemBuffer, Pitch,
496 			pixels, pitch, Width, Height,
497 			FRACUNIT, FRACUNIT, 0, 0);
498 	}
499 	else
500 	{
501 		if (pitch == Pitch)
502 		{
503 			memcpy (pixels, MemBuffer, Width*Height);
504 		}
505 		else
506 		{
507 			for (int y = 0; y < Height; ++y)
508 			{
509 				memcpy ((BYTE *)pixels+y*pitch, MemBuffer+y*Pitch, Width);
510 			}
511 		}
512 	}
513 
514 	if (UsingRenderer)
515 	{
516 		SDL_UnlockTexture (Texture);
517 
518 		SDLFlipCycles.Clock();
519 		SDL_RenderClear(Renderer);
520 		SDL_RenderCopy(Renderer, Texture, NULL, NULL);
521 		SDL_RenderPresent(Renderer);
522 		SDLFlipCycles.Unclock();
523 	}
524 	else
525 	{
526 		SDL_UnlockSurface (Surface);
527 
528 		SDLFlipCycles.Clock();
529 		SDL_UpdateWindowSurface (Screen);
530 		SDLFlipCycles.Unclock();
531 	}
532 
533 	BlitCycles.Unclock();
534 
535 	if (NeedGammaUpdate)
536 	{
537 		bool Windowed = false;
538 		NeedGammaUpdate = false;
539 		CalcGamma ((Windowed || rgamma == 0.f) ? Gamma : (Gamma * rgamma), GammaTable[0]);
540 		CalcGamma ((Windowed || ggamma == 0.f) ? Gamma : (Gamma * ggamma), GammaTable[1]);
541 		CalcGamma ((Windowed || bgamma == 0.f) ? Gamma : (Gamma * bgamma), GammaTable[2]);
542 		NeedPalUpdate = true;
543 	}
544 
545 	if (NeedPalUpdate)
546 	{
547 		NeedPalUpdate = false;
548 		UpdateColors ();
549 	}
550 }
551 
UpdateColors()552 void SDLFB::UpdateColors ()
553 {
554 	if (NotPaletted)
555 	{
556 		PalEntry palette[256];
557 
558 		for (int i = 0; i < 256; ++i)
559 		{
560 			palette[i].r = GammaTable[0][SourcePalette[i].r];
561 			palette[i].g = GammaTable[1][SourcePalette[i].g];
562 			palette[i].b = GammaTable[2][SourcePalette[i].b];
563 		}
564 		if (FlashAmount)
565 		{
566 			DoBlending (palette, palette,
567 				256, GammaTable[0][Flash.r], GammaTable[1][Flash.g], GammaTable[2][Flash.b],
568 				FlashAmount);
569 		}
570 		GPfx.SetPalette (palette);
571 	}
572 	else
573 	{
574 		SDL_Color colors[256];
575 
576 		for (int i = 0; i < 256; ++i)
577 		{
578 			colors[i].r = GammaTable[0][SourcePalette[i].r];
579 			colors[i].g = GammaTable[1][SourcePalette[i].g];
580 			colors[i].b = GammaTable[2][SourcePalette[i].b];
581 		}
582 		if (FlashAmount)
583 		{
584 			DoBlending ((PalEntry *)colors, (PalEntry *)colors,
585 				256, GammaTable[2][Flash.b], GammaTable[1][Flash.g], GammaTable[0][Flash.r],
586 				FlashAmount);
587 		}
588 		SDL_SetPaletteColors (Surface->format->palette, colors, 0, 256);
589 	}
590 }
591 
GetPalette()592 PalEntry *SDLFB::GetPalette ()
593 {
594 	return SourcePalette;
595 }
596 
UpdatePalette()597 void SDLFB::UpdatePalette ()
598 {
599 	NeedPalUpdate = true;
600 }
601 
SetGamma(float gamma)602 bool SDLFB::SetGamma (float gamma)
603 {
604 	Gamma = gamma;
605 	NeedGammaUpdate = true;
606 	return true;
607 }
608 
SetFlash(PalEntry rgb,int amount)609 bool SDLFB::SetFlash (PalEntry rgb, int amount)
610 {
611 	Flash = rgb;
612 	FlashAmount = amount;
613 	NeedPalUpdate = true;
614 	return true;
615 }
616 
GetFlash(PalEntry & rgb,int & amount)617 void SDLFB::GetFlash (PalEntry &rgb, int &amount)
618 {
619 	rgb = Flash;
620 	amount = FlashAmount;
621 }
622 
623 // Q: Should I gamma adjust the returned palette?
GetFlashedPalette(PalEntry pal[256])624 void SDLFB::GetFlashedPalette (PalEntry pal[256])
625 {
626 	memcpy (pal, SourcePalette, 256*sizeof(PalEntry));
627 	if (FlashAmount)
628 	{
629 		DoBlending (pal, pal, 256, Flash.r, Flash.g, Flash.b, FlashAmount);
630 	}
631 }
632 
SetFullscreen(bool fullscreen)633 void SDLFB::SetFullscreen (bool fullscreen)
634 {
635 	if (IsFullscreen() == fullscreen)
636 		return;
637 
638 	SDL_SetWindowFullscreen (Screen, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
639 	if (!fullscreen)
640 	{
641 		// Restore proper window size
642 		SDL_SetWindowSize (Screen, Width, Height);
643 	}
644 
645 	ResetSDLRenderer ();
646 }
647 
IsFullscreen()648 bool SDLFB::IsFullscreen ()
649 {
650 	return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
651 }
652 
ResetSDLRenderer()653 void SDLFB::ResetSDLRenderer ()
654 {
655 	if (Renderer)
656 	{
657 		if (Texture)
658 			SDL_DestroyTexture (Texture);
659 		SDL_DestroyRenderer (Renderer);
660 	}
661 
662 	UsingRenderer = !vid_forcesurface;
663 	if (UsingRenderer)
664 	{
665 		Renderer = SDL_CreateRenderer (Screen, -1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE|
666 										(vid_vsync ? SDL_RENDERER_PRESENTVSYNC : 0));
667 		if (!Renderer)
668 			return;
669 
670 		SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255);
671 
672 		Uint32 fmt;
673 		switch(vid_displaybits)
674 		{
675 			default: fmt = SDL_PIXELFORMAT_ARGB8888; break;
676 			case 30: fmt = SDL_PIXELFORMAT_ARGB2101010; break;
677 			case 24: fmt = SDL_PIXELFORMAT_RGB888; break;
678 			case 16: fmt = SDL_PIXELFORMAT_RGB565; break;
679 			case 15: fmt = SDL_PIXELFORMAT_ARGB1555; break;
680 		}
681 		Texture = SDL_CreateTexture (Renderer, fmt, SDL_TEXTUREACCESS_STREAMING, Width, Height);
682 
683 		{
684 			NotPaletted = true;
685 
686 			Uint32 format;
687 			SDL_QueryTexture(Texture, &format, NULL, NULL, NULL);
688 
689 			Uint32 Rmask, Gmask, Bmask, Amask;
690 			int bpp;
691 			SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
692 			GPfx.SetFormat (bpp, Rmask, Gmask, Bmask);
693 		}
694 	}
695 	else
696 	{
697 		Surface = SDL_GetWindowSurface (Screen);
698 
699 		if (Surface->format->palette == NULL)
700 		{
701 			NotPaletted = true;
702 			GPfx.SetFormat (Surface->format->BitsPerPixel, Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask);
703 		}
704 		else
705 			NotPaletted = false;
706 	}
707 
708 	// In fullscreen, set logical size according to animorphic ratio.
709 	// Windowed modes are rendered to fill the window (usually 1:1)
710 	if (IsFullscreen ())
711 	{
712 		int w, h;
713 		SDL_GetWindowSize (Screen, &w, &h);
714 		ScaleWithAspect (w, h, Width, Height);
715 		SDL_RenderSetLogicalSize (Renderer, w, h);
716 	}
717 }
718 
SetVSync(bool vsync)719 void SDLFB::SetVSync (bool vsync)
720 {
721 #ifdef __APPLE__
722 	if (CGLContextObj context = CGLGetCurrentContext())
723 	{
724 		// Apply vsync for native backend only (where OpenGL context is set)
725 
726 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
727 		// Inconsistency between 10.4 and 10.5 SDKs:
728 		// third argument of CGLSetParameter() is const long* on 10.4 and const GLint* on 10.5
729 		// So, GLint typedef'ed to long instead of int to workaround this issue
730 		typedef long GLint;
731 #endif // prior to 10.5
732 
733 		const GLint value = vsync ? 1 : 0;
734 		CGLSetParameter(context, kCGLCPSwapInterval, &value);
735 	}
736 #else
737 	ResetSDLRenderer ();
738 #endif // __APPLE__
739 }
740 
ScaleCoordsFromWindow(SWORD & x,SWORD & y)741 void SDLFB::ScaleCoordsFromWindow(SWORD &x, SWORD &y)
742 {
743 	int w, h;
744 	SDL_GetWindowSize (Screen, &w, &h);
745 
746 	// Detect if we're doing scaling in the Window and adjust the mouse
747 	// coordinates accordingly. This could be more efficent, but I
748 	// don't think performance is an issue in the menus.
749 	if(IsFullscreen())
750 	{
751 		int realw = w, realh = h;
752 		ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
753 		if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
754 		{
755 			double xratio = (double)SCREENWIDTH/realw;
756 			double yratio = (double)SCREENHEIGHT/realh;
757 			if (realw < w)
758 			{
759 				x = (x - (w - realw)/2)*xratio;
760 				y *= yratio;
761 			}
762 			else
763 			{
764 				y = (y - (h - realh)/2)*yratio;
765 				x *= xratio;
766 			}
767 		}
768 	}
769 	else
770 	{
771 		x = (SWORD)(x*Width/w);
772 		y = (SWORD)(y*Height/h);
773 	}
774 }
775 
ADD_STAT(blit)776 ADD_STAT (blit)
777 {
778 	FString out;
779 	out.Format ("blit=%04.1f ms  flip=%04.1f ms",
780 		BlitCycles.TimeMS(), SDLFlipCycles.TimeMS());
781 	return out;
782 }
783