1 /*
2 * ppui/sdl/DisplayDeviceFB_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 * 12/5/14 - Dale Whinham
22 * - Port to SDL2
23 * - Resizable window which renders to a scaled texture
24 * - Experimental, buggy Retina support (potential problems with mouse coordinates if letterboxing happens)
25 *
26 * TODO: - Test under Linux (only tested under OSX)
27 * - Test/fix/remove scale factor and orientation code
28 * - Look at the OpenGL stuff
29 */
30
31 #include "DisplayDeviceFB_SDL.h"
32 #include "Graphics.h"
33
PPDisplayDeviceFB(pp_int32 width,pp_int32 height,pp_int32 scaleFactor,pp_int32 bpp,bool fullScreen,Orientations theOrientation,bool swapRedBlue)34 PPDisplayDeviceFB::PPDisplayDeviceFB(pp_int32 width,
35 pp_int32 height,
36 pp_int32 scaleFactor,
37 pp_int32 bpp,
38 bool fullScreen,
39 Orientations theOrientation/* = ORIENTATION_NORMAL*/,
40 bool swapRedBlue/* = false*/) :
41 PPDisplayDevice(width, height, scaleFactor, bpp, fullScreen, theOrientation),
42 needsTemporaryBuffer((orientation != ORIENTATION_NORMAL) || (scaleFactor != 1)),
43 temporaryBuffer(NULL)
44 {
45 // Create an SDL window and surface
46 theWindow = CreateWindow(realWidth, realHeight, bpp,
47 #ifdef HIDPI_SUPPORT
48 SDL_WINDOW_ALLOW_HIGHDPI | // Support for 'Retina'/Hi-DPI displays
49 #endif
50 SDL_WINDOW_RESIZABLE | // MilkyTracker's window is resizable
51 (bFullScreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); // Use 'fake fullscreen' because we can scale
52
53 if (theWindow == NULL)
54 {
55 fprintf(stderr, "SDL: Could not create window.\n");
56 exit(EXIT_FAILURE);
57 }
58
59 // Create renderer for the window
60 theRenderer = SDL_CreateRenderer(theWindow, drv_index, 0);
61 if (theRenderer == NULL)
62 {
63 fprintf(stderr, "SDL: SDL_CreateRenderer failed: %s\n", SDL_GetError());
64 exit(EXIT_FAILURE);
65 }
66
67 #ifdef HIDPI_SUPPORT
68 // Feed SDL_RenderSetLogicalSize() with output size, not GUI surface size, otherwise mouse coordinates will be wrong for Hi-DPI
69 int rendererW, rendererH;
70 SDL_GetRendererOutputSize(theRenderer, &rendererW, &rendererH);
71 #endif
72
73 // Log renderer capabilities
74 SDL_RendererInfo theRendererInfo;
75 if (!SDL_GetRendererInfo(theRenderer, &theRendererInfo))
76 {
77 if (theRendererInfo.flags & SDL_RENDERER_SOFTWARE) printf("SDL: Using software renderer.\n");
78 if (theRendererInfo.flags & SDL_RENDERER_ACCELERATED) printf("SDL: Using accelerated renderer.\n");
79 if (theRendererInfo.flags & SDL_RENDERER_PRESENTVSYNC) printf("SDL: Vsync enabled.\n");
80 if (theRendererInfo.flags & SDL_RENDERER_TARGETTEXTURE) printf("SDL: Renderer supports rendering to texture.\n");
81 }
82
83 // Lock aspect ratio and scale the UI up to fit the window
84 #ifdef HIDPI_SUPPORT
85 SDL_RenderSetLogicalSize(theRenderer, rendererW, rendererH);
86 #else
87 SDL_RenderSetLogicalSize(theRenderer, realWidth, realHeight);
88 #endif
89
90 // Use linear filtering for the scaling (make this optional eventually)
91 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
92
93 // Create surface for rendering graphics
94 theSurface = SDL_CreateRGBSurface(0, realWidth, realHeight, bpp == -1 ? 32 : bpp, 0, 0, 0, 0);
95 if (theSurface == NULL)
96 {
97 fprintf(stderr, "SDL: SDL_CreateSurface failed: %s\n", SDL_GetError());
98 exit(EXIT_FAILURE);
99 }
100
101 // Streaming texture for rendering the UI
102 theTexture = SDL_CreateTexture(theRenderer, theSurface->format->format, SDL_TEXTUREACCESS_STREAMING, realWidth, realHeight);
103 if (theTexture == NULL)
104 {
105 fprintf(stderr, "SDL: SDL_CreateTexture failed: %s\n", SDL_GetError());
106 exit(EXIT_FAILURE);
107 }
108
109 // We got a surface: update bpp value
110 bpp = theSurface->format->BitsPerPixel;
111
112 // Create a PPGraphics context based on bpp
113 switch (bpp)
114 {
115 case 16:
116 currentGraphics = new PPGraphics_16BIT(width, height, 0, NULL);
117 break;
118
119 case 24:
120 {
121 PPGraphics_24bpp_generic* g = new PPGraphics_24bpp_generic(width, height, 0, NULL);
122 if (swapRedBlue)
123 {
124 g->setComponentBitpositions(theSurface->format->Bshift,
125 theSurface->format->Gshift,
126 theSurface->format->Rshift);
127 }
128 else
129 {
130 g->setComponentBitpositions(theSurface->format->Rshift,
131 theSurface->format->Gshift,
132 theSurface->format->Bshift);
133 }
134 currentGraphics = static_cast<PPGraphicsAbstract*>(g);
135 break;
136 }
137
138 case 32:
139 {
140 PPGraphics_32bpp_generic* g = new PPGraphics_32bpp_generic(width, height, 0, NULL);
141 if (swapRedBlue)
142 {
143 g->setComponentBitpositions(theSurface->format->Bshift,
144 theSurface->format->Gshift,
145 theSurface->format->Rshift);
146 }
147 else
148 {
149 g->setComponentBitpositions(theSurface->format->Rshift,
150 theSurface->format->Gshift,
151 theSurface->format->Bshift);
152 }
153 currentGraphics = static_cast<PPGraphicsAbstract*>(g);
154 break;
155 }
156
157 default:
158 fprintf(stderr, "SDL: Unsupported color depth (%i), try either 16, 24 or 32", bpp);
159 exit(EXIT_FAILURE);
160 }
161
162 if (needsTemporaryBuffer)
163 {
164 temporaryBufferPitch = (width*bpp)/8;
165 temporaryBufferBPP = bpp;
166 temporaryBuffer = new pp_uint8[getSize().width*getSize().height*(bpp/8)];
167 }
168
169 currentGraphics->lock = true;
170 }
171
~PPDisplayDeviceFB()172 PPDisplayDeviceFB::~PPDisplayDeviceFB()
173 {
174 SDL_FreeSurface(theSurface);
175 SDL_DestroyRenderer(theRenderer);
176 SDL_DestroyWindow(theWindow);
177
178 delete[] temporaryBuffer;
179 // base class is responsible for deleting currentGraphics
180 }
181
open()182 PPGraphicsAbstract* PPDisplayDeviceFB::open()
183 {
184 if (!isEnabled())
185 return NULL;
186
187 if (currentGraphics->lock)
188 {
189 if (SDL_LockSurface(theSurface) < 0)
190 return NULL;
191
192 currentGraphics->lock = false;
193
194 if (needsTemporaryBuffer)
195 static_cast<PPGraphicsFrameBuffer*>(currentGraphics)->setBufferProperties(temporaryBufferPitch, (pp_uint8*)temporaryBuffer);
196 else
197 static_cast<PPGraphicsFrameBuffer*>(currentGraphics)->setBufferProperties(theSurface->pitch, (pp_uint8*)theSurface->pixels);
198
199 return currentGraphics;
200 }
201
202 return NULL;
203 }
204
close()205 void PPDisplayDeviceFB::close()
206 {
207 SDL_UnlockSurface(theSurface);
208
209 currentGraphics->lock = true;
210 }
211
update()212 void PPDisplayDeviceFB::update()
213 {
214 if (!isUpdateAllowed() || !isEnabled())
215 return;
216
217 if (theSurface->locked)
218 {
219 return;
220 }
221
222 PPRect r(0, 0, getSize().width, getSize().height);
223 swap(r);
224
225 // Update entire texture and copy to renderer
226 SDL_UpdateTexture(theTexture, NULL, theSurface->pixels, theSurface->pitch);
227 SDL_RenderClear(theRenderer);
228 SDL_RenderCopy(theRenderer, theTexture, NULL, NULL);
229 SDL_RenderPresent(theRenderer);
230 }
231
update(const PPRect & r)232 void PPDisplayDeviceFB::update(const PPRect& r)
233 {
234 if (!isUpdateAllowed() || !isEnabled())
235 return;
236
237 if (theSurface->locked)
238 {
239 return;
240 }
241
242 swap(r);
243
244 PPRect r2(r);
245 r2.scale(scaleFactor);
246
247 transformInverse(r2);
248
249 SDL_Rect r3 = { r2.x1, r2.y1, r2.width(), r2.height() };
250
251 // Calculate destination pixel data offset based on row pitch and x coordinate
252 void* surfaceOffset = (char*) theSurface->pixels + r2.y1 * theSurface->pitch + r2.x1 * theSurface->format->BytesPerPixel;
253
254 // Update dirty area of texture and copy to renderer
255 SDL_UpdateTexture(theTexture, &r3, surfaceOffset, theSurface->pitch);
256 SDL_RenderClear(theRenderer);
257 SDL_RenderCopy(theRenderer, theTexture, NULL, NULL);
258 SDL_RenderPresent(theRenderer);
259 }
260
swap(const PPRect & r2)261 void PPDisplayDeviceFB::swap(const PPRect& r2)
262 {
263 PPRect r(r2);
264 pp_int32 h;
265 if (r.x2 < r.x1)
266 {
267 h = r.x1; r.x1 = r.x2; r.x2 = h;
268 }
269 if (r.y2 < r.y1)
270 {
271 h = r.y1; r.y1 = r.y2; r.y2 = h;
272 }
273
274 switch (orientation)
275 {
276 case ORIENTATION_NORMAL:
277 {
278 if (!needsTemporaryBuffer)
279 return;
280
281 if (SDL_LockSurface(theSurface) < 0)
282 return;
283
284 const pp_uint32 srcBPP = temporaryBufferBPP/8;
285 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
286
287 PPRect destRect(r);
288 destRect.scale(scaleFactor);
289
290 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
291 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
292
293 switch (temporaryBufferBPP)
294 {
295 case 16:
296 {
297 pp_uint32 srcPitch = temporaryBufferPitch;
298 pp_uint32 dstPitch = theSurface->pitch;
299
300 pp_uint8* src = (pp_uint8*)temporaryBuffer;
301 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
302
303 pp_uint32 v = r.y1 * 65536;
304 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
305 {
306 pp_uint32 u = r.x1 * 65536;
307 pp_uint16* dstPtr = (pp_uint16*)(dst + y*dstPitch + destRect.x1*dstBPP);
308 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
309 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
310 {
311 *dstPtr++ = *(pp_uint16*)(srcPtr + (u>>16) * srcBPP);
312 u += stepU;
313 }
314 v += stepV;
315 }
316
317
318 break;
319 }
320
321 case 24:
322 {
323 pp_uint32 srcPitch = temporaryBufferPitch;
324 pp_uint32 dstPitch = theSurface->pitch;
325
326 pp_uint8* src = (pp_uint8*)temporaryBuffer;
327 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
328
329 const pp_uint32 srcBPP = temporaryBufferBPP/8;
330 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
331
332 pp_uint32 v = r.y1 * 65536;
333 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
334 {
335 pp_uint32 u = r.x1 * 65536;
336 pp_uint8* dstPtr = (pp_uint8*)(dst + y*dstPitch + destRect.x1*dstBPP);
337 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
338 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
339 {
340 *dstPtr = *(pp_uint8*)(srcPtr + (u>>16) * srcBPP);
341 *(dstPtr+1) = *(pp_uint8*)(srcPtr + (u>>16) * srcBPP + 1);
342 *(dstPtr+2) = *(pp_uint8*)(srcPtr + (u>>16) * srcBPP + 2);
343 dstPtr+=3;
344 u += stepU;
345 }
346 v += stepV;
347 }
348
349 break;
350 }
351
352 case 32:
353 {
354 pp_uint32 srcPitch = temporaryBufferPitch;
355 pp_uint32 dstPitch = theSurface->pitch;
356
357 pp_uint8* src = (pp_uint8*)temporaryBuffer;
358 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
359
360 const pp_uint32 srcBPP = temporaryBufferBPP/8;
361 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
362
363 pp_uint32 v = r.y1 * 65536;
364 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
365 {
366 pp_uint32 u = r.x1 * 65536;
367 pp_uint32* dstPtr = (pp_uint32*)(dst + y*dstPitch + destRect.x1*dstBPP);
368 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
369 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
370 {
371 *dstPtr++ = *(pp_uint32*)(srcPtr + (u>>16) * srcBPP);
372 u += stepU;
373 }
374 v += stepV;
375 }
376
377 break;
378 }
379
380 default:
381 fprintf(stderr, "SDL: Unsupported color depth for requested orientation");
382 exit(2);
383 }
384
385 SDL_UnlockSurface(theSurface);
386
387 break;
388 }
389
390 case ORIENTATION_ROTATE90CCW:
391 {
392 if (SDL_LockSurface(theSurface) < 0)
393 return;
394
395 switch (temporaryBufferBPP)
396 {
397 case 16:
398 {
399 pp_uint32 srcPitch = temporaryBufferPitch >> 1;
400 pp_uint32 dstPitch = theSurface->pitch >> 1;
401
402 pp_uint16* src = (pp_uint16*)temporaryBuffer;
403 pp_uint16* dst = (pp_uint16*)theSurface->pixels;
404
405 if (scaleFactor != 1)
406 {
407 PPRect destRect(r);
408 destRect.scale(scaleFactor);
409
410 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
411 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
412
413 pp_uint32 v = r.y1 * 65536;
414 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
415 {
416 pp_uint32 u = r.x1 * 65536;
417 pp_uint16* srcPtr = src + (v>>16)*srcPitch;
418 pp_uint16* dstPtr = dst + y + (realHeight-destRect.x1)*dstPitch;
419 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
420 {
421 *(dstPtr-=dstPitch) = *(srcPtr+(u>>16));
422
423 u += stepU;
424 }
425 v += stepV;
426 }
427 }
428 else
429 {
430 for (pp_uint32 y = r.y1; y < r.y2; y++)
431 {
432 pp_uint16* srcPtr = src + y*srcPitch + r.x1;
433 pp_uint16* dstPtr = dst + y + (realHeight-r.x1)*dstPitch;
434 for (pp_uint32 x = r.x1; x < r.x2; x++)
435 *(dstPtr-=dstPitch) = *srcPtr++;
436 }
437 }
438
439 break;
440 }
441
442 case 24:
443 {
444 pp_uint32 srcPitch = temporaryBufferPitch;
445 pp_uint32 dstPitch = theSurface->pitch;
446
447 pp_uint8* src = (pp_uint8*)temporaryBuffer;
448 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
449
450 const pp_uint32 srcBPP = temporaryBufferBPP/8;
451 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
452
453 if (scaleFactor != 1)
454 {
455 PPRect destRect(r);
456 destRect.scale(scaleFactor);
457
458 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
459 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
460
461 pp_uint32 v = r.y1 * 65536;
462 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
463 {
464 pp_uint32 u = r.x1 * 65536;
465 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
466 pp_uint8* dstPtr = dst + y*dstBPP + dstPitch*(realHeight-1-destRect.x1);
467 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
468 {
469 dstPtr[0] = *(srcPtr+(u>>16) * srcBPP);
470 dstPtr[1] = *(srcPtr+(u>>16) * srcBPP + 1);
471 dstPtr[2] = *(srcPtr+(u>>16) * srcBPP + 2);
472 dstPtr-=dstPitch;
473
474 u += stepU;
475 }
476 v += stepV;
477 }
478 }
479 else
480 {
481 for (pp_uint32 y = r.y1; y < r.y2; y++)
482 {
483 pp_uint8* srcPtr = src + y*srcPitch + r.x1*srcBPP;
484 pp_uint8* dstPtr = dst + y*dstBPP + dstPitch*(realHeight-1-r.x1);
485 for (pp_uint32 x = r.x1; x < r.x2; x++)
486 {
487 dstPtr[0] = srcPtr[0];
488 dstPtr[1] = srcPtr[1];
489 dstPtr[2] = srcPtr[2];
490 srcPtr+=srcBPP;
491 dstPtr-=dstPitch;
492 }
493 }
494 }
495
496 break;
497 }
498
499 case 32:
500 {
501 pp_uint32 srcPitch = temporaryBufferPitch;
502 pp_uint32 dstPitch = theSurface->pitch;
503
504 pp_uint8* src = (pp_uint8*)temporaryBuffer;
505 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
506
507 const pp_uint32 srcBPP = temporaryBufferBPP/8;
508 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
509
510 if (scaleFactor != 1)
511 {
512 PPRect destRect(r);
513 destRect.scale(scaleFactor);
514
515 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
516 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
517
518 pp_uint32 v = r.y1 * 65536;
519 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
520 {
521 pp_uint32 u = r.x1 * 65536;
522 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
523 pp_uint32* dstPtr = (pp_uint32*)(dst + y*dstBPP + dstPitch*(realHeight-1-destRect.x1));
524 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
525 {
526 *(dstPtr-=(dstPitch>>2)) = *(pp_uint32*)(srcPtr + (u>>16) * srcBPP);
527 u += stepU;
528 }
529 v += stepV;
530 }
531 }
532 else
533 {
534 for (pp_uint32 y = r.y1; y < r.y2; y++)
535 {
536 pp_uint32* srcPtr = (pp_uint32*)(src + y*srcPitch + r.x1*srcBPP);
537 pp_uint32* dstPtr = (pp_uint32*)(dst + y*dstBPP + dstPitch*(realHeight-1-r.x1));
538 for (pp_uint32 x = r.x1; x < r.x2; x++)
539 *(dstPtr-=(dstPitch>>2)) = *srcPtr++;
540 }
541 }
542
543 break;
544 }
545
546 default:
547 fprintf(stderr, "SDL: Unsupported color depth for requested orientation");
548 exit(2);
549 }
550
551 SDL_UnlockSurface(theSurface);
552 break;
553 }
554
555 case ORIENTATION_ROTATE90CW:
556 {
557 if (SDL_LockSurface(theSurface) < 0)
558 return;
559
560 switch (temporaryBufferBPP)
561 {
562 case 16:
563 {
564 pp_uint32 srcPitch = temporaryBufferPitch >> 1;
565 pp_uint32 dstPitch = theSurface->pitch >> 1;
566
567 pp_uint16* src = (pp_uint16*)temporaryBuffer;
568 pp_uint16* dst = (pp_uint16*)theSurface->pixels;
569
570 if (scaleFactor != 1)
571 {
572 PPRect destRect(r);
573 destRect.scale(scaleFactor);
574
575 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
576 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
577
578 pp_uint32 v = r.y1 * 65536;
579 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
580 {
581 pp_uint32 u = r.x1 * 65536;
582 pp_uint16* srcPtr = src + (v>>16)*srcPitch;
583 pp_uint16* dstPtr = dst + (realWidth-1-y) + (dstPitch*(destRect.x1));
584 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
585 {
586 *(dstPtr+=dstPitch) = *(srcPtr+(u>>16));
587
588 u += stepU;
589 }
590 v += stepV;
591 }
592 }
593 else
594 {
595 for (pp_uint32 y = r.y1; y < r.y2; y++)
596 {
597 pp_uint16* srcPtr = src + y*srcPitch + r.x1;
598 pp_uint16* dstPtr = dst + (realWidth-1-y) + (dstPitch*r.x1);
599 for (pp_uint32 x = r.x1; x < r.x2; x++)
600 *(dstPtr+=dstPitch) = *srcPtr++;
601 }
602 }
603
604 break;
605 }
606
607 case 24:
608 {
609 pp_uint32 srcPitch = temporaryBufferPitch;
610 pp_uint32 dstPitch = theSurface->pitch;
611
612 pp_uint8* src = (pp_uint8*)temporaryBuffer;
613 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
614
615 const pp_uint32 srcBPP = temporaryBufferBPP/8;
616 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
617
618 if (scaleFactor != 1)
619 {
620 PPRect destRect(r);
621 destRect.scale(scaleFactor);
622
623 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
624 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
625
626 pp_uint32 v = r.y1 * 65536;
627 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
628 {
629 pp_uint32 u = r.x1 * 65536;
630 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
631 pp_uint8* dstPtr = dst + (realWidth-1-y)*dstBPP + (dstPitch*(destRect.x1));
632 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
633 {
634 dstPtr[0] = *(srcPtr+(u>>16) * srcBPP);
635 dstPtr[1] = *(srcPtr+(u>>16) * srcBPP + 1);
636 dstPtr[2] = *(srcPtr+(u>>16) * srcBPP + 2);
637 dstPtr+=dstPitch;
638
639 u += stepU;
640 }
641 v += stepV;
642 }
643 }
644 else
645 {
646 for (pp_uint32 y = r.y1; y < r.y2; y++)
647 {
648 pp_uint8* srcPtr = src + y*srcPitch + r.x1*srcBPP;
649 pp_uint8* dstPtr = dst + (realWidth-1-y)*dstBPP + (dstPitch*r.x1);
650 for (pp_uint32 x = r.x1; x < r.x2; x++)
651 {
652 dstPtr[0] = srcPtr[0];
653 dstPtr[1] = srcPtr[1];
654 dstPtr[2] = srcPtr[2];
655 srcPtr+=srcBPP;
656 dstPtr+=dstPitch;
657 }
658 }
659 }
660
661 break;
662 }
663
664 case 32:
665 {
666 pp_uint32 srcPitch = temporaryBufferPitch;
667 pp_uint32 dstPitch = theSurface->pitch;
668
669 pp_uint8* src = (pp_uint8*)temporaryBuffer;
670 pp_uint8* dst = (pp_uint8*)theSurface->pixels;
671
672 const pp_uint32 srcBPP = temporaryBufferBPP/8;
673 const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
674
675 if (scaleFactor != 1)
676 {
677 PPRect destRect(r);
678 destRect.scale(scaleFactor);
679
680 const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
681 const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
682
683 pp_uint32 v = r.y1 * 65536;
684 for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
685 {
686 pp_uint32 u = r.x1 * 65536;
687 pp_uint8* srcPtr = src + (v>>16)*srcPitch;
688 pp_uint32* dstPtr = (pp_uint32*)(dst + (realWidth-1-y)*dstBPP + (dstPitch*(destRect.x1)));
689 for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
690 {
691 *(dstPtr+=(dstPitch>>2)) = *(pp_uint32*)(srcPtr + (u>>16) * srcBPP);
692 u += stepU;
693 }
694 v += stepV;
695 }
696 }
697 else
698 {
699 for (pp_uint32 y = r.y1; y < r.y2; y++)
700 {
701 pp_uint32* srcPtr = (pp_uint32*)(src + y*srcPitch + r.x1*srcBPP);
702 pp_uint32* dstPtr = (pp_uint32*)(dst + (realWidth-1-y)*dstBPP + (dstPitch*r.x1));
703 for (pp_uint32 x = r.x1; x < r.x2; x++)
704 *(dstPtr+=(dstPitch>>2)) = *srcPtr++;
705 }
706 }
707
708 break;
709 }
710
711 default:
712 fprintf(stderr, "SDL: Unsupported color depth for requested orientation");
713 exit(EXIT_FAILURE);
714 }
715
716 SDL_UnlockSurface(theSurface);
717 break;
718 }
719 }
720
721 }
722
723 // This is unused at the moment, could be useful if we manage to get the GUI resizable in the future.
setSize(const PPSize & size)724 void PPDisplayDeviceFB::setSize(const PPSize& size)
725 {
726 this->size = size;
727 theSurface = SDL_CreateRGBSurface(0, size.width, size.height, theSurface->format->BitsPerPixel, 0, 0, 0, 0);
728 theTexture = SDL_CreateTextureFromSurface(theRenderer, theSurface);
729 theRenderer = SDL_GetRenderer(theWindow);
730 }
731