SDL  2.0
SDL_render_sw.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if !SDL_RENDER_DISABLED
24 
25 #include "../SDL_sysrender.h"
26 #include "SDL_render_sw_c.h"
27 #include "SDL_hints.h"
28 
29 #include "SDL_draw.h"
30 #include "SDL_blendfillrect.h"
31 #include "SDL_blendline.h"
32 #include "SDL_blendpoint.h"
33 #include "SDL_drawline.h"
34 #include "SDL_drawpoint.h"
35 #include "SDL_rotate.h"
36 
37 /* SDL surface based renderer implementation */
38 
41  const SDL_WindowEvent *event);
42 static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
51  const SDL_Rect * rect, const void *pixels,
52  int pitch);
54  const SDL_Rect * rect, void **pixels, int *pitch);
61  const SDL_FPoint * points, int count);
63  const SDL_FPoint * points, int count);
65  const SDL_FRect * rects, int count);
67  const SDL_Rect * srcrect, const SDL_FRect * dstrect);
69  const SDL_Rect * srcrect, const SDL_FRect * dstrect,
70  const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
72  Uint32 format, void * pixels, int pitch);
76 
77 
80  {
81  "software",
83  8,
84  {
93  },
94  0,
95  0}
96 };
97 
98 typedef struct
99 {
102 } SW_RenderData;
103 
104 
105 static SDL_Surface *
107 {
108  SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
109 
110  if (!data->surface) {
111  data->surface = data->window;
112  }
113  if (!data->surface) {
115  if (surface) {
116  data->surface = data->window = surface;
117 
118  SW_UpdateViewport(renderer);
119  SW_UpdateClipRect(renderer);
120  }
121  }
122  return data->surface;
123 }
124 
125 SDL_Renderer *
127 {
130 
131  if (!surface) {
132  SDL_SetError("Can't create renderer for NULL surface");
133  return NULL;
134  }
135 
136  renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
137  if (!renderer) {
138  SDL_OutOfMemory();
139  return NULL;
140  }
141 
142  data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
143  if (!data) {
144  SW_DestroyRenderer(renderer);
145  SDL_OutOfMemory();
146  return NULL;
147  }
148  data->surface = surface;
149  data->window = surface;
150 
151  renderer->WindowEvent = SW_WindowEvent;
152  renderer->GetOutputSize = SW_GetOutputSize;
153  renderer->CreateTexture = SW_CreateTexture;
157  renderer->UpdateTexture = SW_UpdateTexture;
158  renderer->LockTexture = SW_LockTexture;
159  renderer->UnlockTexture = SW_UnlockTexture;
161  renderer->UpdateViewport = SW_UpdateViewport;
162  renderer->UpdateClipRect = SW_UpdateClipRect;
163  renderer->RenderClear = SW_RenderClear;
167  renderer->RenderCopy = SW_RenderCopy;
168  renderer->RenderCopyEx = SW_RenderCopyEx;
170  renderer->RenderPresent = SW_RenderPresent;
171  renderer->DestroyTexture = SW_DestroyTexture;
173  renderer->info = SW_RenderDriver.info;
174  renderer->driverdata = data;
175 
176  SW_ActivateRenderer(renderer);
177 
178  return renderer;
179 }
180 
181 SDL_Renderer *
183 {
185 
186  surface = SDL_GetWindowSurface(window);
187  if (!surface) {
188  return NULL;
189  }
190  return SW_CreateRendererForSurface(surface);
191 }
192 
193 static void
195 {
196  SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
197 
198  if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
199  data->surface = NULL;
200  data->window = NULL;
201  }
202 }
203 
204 static int
206 {
208 
209  if (surface) {
210  if (w) {
211  *w = surface->w;
212  }
213  if (h) {
214  *h = surface->h;
215  }
216  return 0;
217  } else {
218  SDL_SetError("Software renderer doesn't have an output surface");
219  return -1;
220  }
221 }
222 
223 static int
225 {
226  int bpp;
227  Uint32 Rmask, Gmask, Bmask, Amask;
228 
230  (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
231  return SDL_SetError("Unknown texture format");
232  }
233 
234  texture->driverdata =
235  SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,
236  Bmask, Amask);
237  SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,
238  texture->b);
239  SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);
240  SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);
241 
242  /* Only RLE encode textures without an alpha channel since the RLE coder
243  * discards the color values of pixels with an alpha value of zero.
244  */
245  if (texture->access == SDL_TEXTUREACCESS_STATIC && !Amask) {
246  SDL_SetSurfaceRLE(texture->driverdata, 1);
247  }
248 
249  if (!texture->driverdata) {
250  return -1;
251  }
252  return 0;
253 }
254 
255 static int
257 {
258  SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
259  /* If the color mod is ever enabled (non-white), permanently disable RLE (which doesn't support
260  * color mod) to avoid potentially frequent RLE encoding/decoding.
261  */
262  if ((texture->r & texture->g & texture->b) != 255) {
263  SDL_SetSurfaceRLE(surface, 0);
264  }
265  return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
266  texture->b);
267 }
268 
269 static int
271 {
272  SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
273  /* If the texture ever has multiple alpha values (surface alpha plus alpha channel), permanently
274  * disable RLE (which doesn't support this) to avoid potentially frequent RLE encoding/decoding.
275  */
276  if (texture->a != 255 && surface->format->Amask) {
277  SDL_SetSurfaceRLE(surface, 0);
278  }
279  return SDL_SetSurfaceAlphaMod(surface, texture->a);
280 }
281 
282 static int
284 {
285  SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
286  /* If add or mod blending are ever enabled, permanently disable RLE (which doesn't support
287  * them) to avoid potentially frequent RLE encoding/decoding.
288  */
289  if ((texture->blendMode == SDL_BLENDMODE_ADD || texture->blendMode == SDL_BLENDMODE_MOD)) {
290  SDL_SetSurfaceRLE(surface, 0);
291  }
292  return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
293 }
294 
295 static int
297  const SDL_Rect * rect, const void *pixels, int pitch)
298 {
299  SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
300  Uint8 *src, *dst;
301  int row;
302  size_t length;
303 
304  if(SDL_MUSTLOCK(surface))
305  SDL_LockSurface(surface);
306  src = (Uint8 *) pixels;
307  dst = (Uint8 *) surface->pixels +
308  rect->y * surface->pitch +
309  rect->x * surface->format->BytesPerPixel;
310  length = rect->w * surface->format->BytesPerPixel;
311  for (row = 0; row < rect->h; ++row) {
312  SDL_memcpy(dst, src, length);
313  src += pitch;
314  dst += surface->pitch;
315  }
316  if(SDL_MUSTLOCK(surface))
317  SDL_UnlockSurface(surface);
318  return 0;
319 }
320 
321 static int
323  const SDL_Rect * rect, void **pixels, int *pitch)
324 {
325  SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
326 
327  *pixels =
328  (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch +
329  rect->x * surface->format->BytesPerPixel);
330  *pitch = surface->pitch;
331  return 0;
332 }
333 
334 static void
336 {
337 }
338 
339 static int
341 {
342  SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
343 
344  if (texture ) {
345  data->surface = (SDL_Surface *) texture->driverdata;
346  } else {
347  data->surface = data->window;
348  }
349  return 0;
350 }
351 
352 static int
354 {
355  SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
356  SDL_Surface *surface = data->surface;
357 
358  if (!surface) {
359  /* We'll update the viewport after we recreate the surface */
360  return 0;
361  }
362 
363  SDL_SetClipRect(data->surface, &renderer->viewport);
364  return 0;
365 }
366 
367 static int
369 {
370  SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
371  SDL_Surface *surface = data->surface;
372  if (surface) {
373  if (renderer->clipping_enabled) {
374  SDL_Rect clip_rect;
375  clip_rect = renderer->clip_rect;
376  clip_rect.x += renderer->viewport.x;
377  clip_rect.y += renderer->viewport.y;
378  SDL_IntersectRect(&renderer->viewport, &clip_rect, &clip_rect);
379  SDL_SetClipRect(surface, &clip_rect);
380  } else {
381  SDL_SetClipRect(surface, &renderer->viewport);
382  }
383  }
384  return 0;
385 }
386 
387 static int
389 {
391  Uint32 color;
392  SDL_Rect clip_rect;
393 
394  if (!surface) {
395  return -1;
396  }
397 
398  color = SDL_MapRGBA(surface->format,
399  renderer->r, renderer->g, renderer->b, renderer->a);
400 
401  /* By definition the clear ignores the clip rect */
402  clip_rect = surface->clip_rect;
403  SDL_SetClipRect(surface, NULL);
404  SDL_FillRect(surface, NULL, color);
405  SDL_SetClipRect(surface, &clip_rect);
406  return 0;
407 }
408 
409 static int
411  int count)
412 {
414  SDL_Point *final_points;
415  int i, status;
416 
417  if (!surface) {
418  return -1;
419  }
420 
421  final_points = SDL_stack_alloc(SDL_Point, count);
422  if (!final_points) {
423  return SDL_OutOfMemory();
424  }
425  if (renderer->viewport.x || renderer->viewport.y) {
426  int x = renderer->viewport.x;
427  int y = renderer->viewport.y;
428 
429  for (i = 0; i < count; ++i) {
430  final_points[i].x = (int)(x + points[i].x);
431  final_points[i].y = (int)(y + points[i].y);
432  }
433  } else {
434  for (i = 0; i < count; ++i) {
435  final_points[i].x = (int)points[i].x;
436  final_points[i].y = (int)points[i].y;
437  }
438  }
439 
440  /* Draw the points! */
441  if (renderer->blendMode == SDL_BLENDMODE_NONE) {
442  Uint32 color = SDL_MapRGBA(surface->format,
443  renderer->r, renderer->g, renderer->b,
444  renderer->a);
445 
446  status = SDL_DrawPoints(surface, final_points, count, color);
447  } else {
448  status = SDL_BlendPoints(surface, final_points, count,
449  renderer->blendMode,
450  renderer->r, renderer->g, renderer->b,
451  renderer->a);
452  }
453  SDL_stack_free(final_points);
454 
455  return status;
456 }
457 
458 static int
460  int count)
461 {
463  SDL_Point *final_points;
464  int i, status;
465 
466  if (!surface) {
467  return -1;
468  }
469 
470  final_points = SDL_stack_alloc(SDL_Point, count);
471  if (!final_points) {
472  return SDL_OutOfMemory();
473  }
474  if (renderer->viewport.x || renderer->viewport.y) {
475  int x = renderer->viewport.x;
476  int y = renderer->viewport.y;
477 
478  for (i = 0; i < count; ++i) {
479  final_points[i].x = (int)(x + points[i].x);
480  final_points[i].y = (int)(y + points[i].y);
481  }
482  } else {
483  for (i = 0; i < count; ++i) {
484  final_points[i].x = (int)points[i].x;
485  final_points[i].y = (int)points[i].y;
486  }
487  }
488 
489  /* Draw the lines! */
490  if (renderer->blendMode == SDL_BLENDMODE_NONE) {
491  Uint32 color = SDL_MapRGBA(surface->format,
492  renderer->r, renderer->g, renderer->b,
493  renderer->a);
494 
495  status = SDL_DrawLines(surface, final_points, count, color);
496  } else {
497  status = SDL_BlendLines(surface, final_points, count,
498  renderer->blendMode,
499  renderer->r, renderer->g, renderer->b,
500  renderer->a);
501  }
502  SDL_stack_free(final_points);
503 
504  return status;
505 }
506 
507 static int
509 {
511  SDL_Rect *final_rects;
512  int i, status;
513 
514  if (!surface) {
515  return -1;
516  }
517 
518  final_rects = SDL_stack_alloc(SDL_Rect, count);
519  if (!final_rects) {
520  return SDL_OutOfMemory();
521  }
522  if (renderer->viewport.x || renderer->viewport.y) {
523  int x = renderer->viewport.x;
524  int y = renderer->viewport.y;
525 
526  for (i = 0; i < count; ++i) {
527  final_rects[i].x = (int)(x + rects[i].x);
528  final_rects[i].y = (int)(y + rects[i].y);
529  final_rects[i].w = SDL_max((int)rects[i].w, 1);
530  final_rects[i].h = SDL_max((int)rects[i].h, 1);
531  }
532  } else {
533  for (i = 0; i < count; ++i) {
534  final_rects[i].x = (int)rects[i].x;
535  final_rects[i].y = (int)rects[i].y;
536  final_rects[i].w = SDL_max((int)rects[i].w, 1);
537  final_rects[i].h = SDL_max((int)rects[i].h, 1);
538  }
539  }
540 
541  if (renderer->blendMode == SDL_BLENDMODE_NONE) {
542  Uint32 color = SDL_MapRGBA(surface->format,
543  renderer->r, renderer->g, renderer->b,
544  renderer->a);
545  status = SDL_FillRects(surface, final_rects, count, color);
546  } else {
547  status = SDL_BlendFillRects(surface, final_rects, count,
548  renderer->blendMode,
549  renderer->r, renderer->g, renderer->b,
550  renderer->a);
551  }
552  SDL_stack_free(final_rects);
553 
554  return status;
555 }
556 
557 static int
559  const SDL_Rect * srcrect, const SDL_FRect * dstrect)
560 {
562  SDL_Surface *src = (SDL_Surface *) texture->driverdata;
563  SDL_Rect final_rect;
564 
565  if (!surface) {
566  return -1;
567  }
568 
569  if (renderer->viewport.x || renderer->viewport.y) {
570  final_rect.x = (int)(renderer->viewport.x + dstrect->x);
571  final_rect.y = (int)(renderer->viewport.y + dstrect->y);
572  } else {
573  final_rect.x = (int)dstrect->x;
574  final_rect.y = (int)dstrect->y;
575  }
576  final_rect.w = (int)dstrect->w;
577  final_rect.h = (int)dstrect->h;
578 
579  if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
580  return SDL_BlitSurface(src, srcrect, surface, &final_rect);
581  } else {
582  /* If scaling is ever done, permanently disable RLE (which doesn't support scaling)
583  * to avoid potentially frequent RLE encoding/decoding.
584  */
585  SDL_SetSurfaceRLE(surface, 0);
586  return SDL_BlitScaled(src, srcrect, surface, &final_rect);
587  }
588 }
589 
590 static int
592 {
593  const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
594 
595  if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
596  return 0;
597  } else {
598  return 1;
599  }
600 }
601 
602 static int
604  const SDL_Rect * srcrect, const SDL_FRect * dstrect,
605  const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
606 {
608  SDL_Surface *src = (SDL_Surface *) texture->driverdata;
609  SDL_Rect final_rect, tmp_rect;
610  SDL_Surface *src_clone, *src_rotated, *src_scaled;
611  SDL_Surface *mask = NULL, *mask_rotated = NULL;
612  int retval = 0, dstwidth, dstheight, abscenterx, abscentery;
613  double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
614  SDL_BlendMode blendmode;
615  Uint8 alphaMod, rMod, gMod, bMod;
616  int applyModulation = SDL_FALSE;
617  int blitRequired = SDL_FALSE;
618  int isOpaque = SDL_FALSE;
619 
620  if (!surface) {
621  return -1;
622  }
623 
624  if (renderer->viewport.x || renderer->viewport.y) {
625  final_rect.x = (int)(renderer->viewport.x + dstrect->x);
626  final_rect.y = (int)(renderer->viewport.y + dstrect->y);
627  } else {
628  final_rect.x = (int)dstrect->x;
629  final_rect.y = (int)dstrect->y;
630  }
631  final_rect.w = (int)dstrect->w;
632  final_rect.h = (int)dstrect->h;
633 
634  tmp_rect = final_rect;
635  tmp_rect.x = 0;
636  tmp_rect.y = 0;
637 
638  /* It is possible to encounter an RLE encoded surface here and locking it is
639  * necessary because this code is going to access the pixel buffer directly.
640  */
641  if (SDL_MUSTLOCK(src)) {
642  SDL_LockSurface(src);
643  }
644 
645  /* Clone the source surface but use its pixel buffer directly.
646  * The original source surface must be treated as read-only.
647  */
648  src_clone = SDL_CreateRGBSurfaceFrom(src->pixels, src->w, src->h, src->format->BitsPerPixel, src->pitch,
649  src->format->Rmask, src->format->Gmask,
650  src->format->Bmask, src->format->Amask);
651  if (src_clone == NULL) {
652  if (SDL_MUSTLOCK(src)) {
653  SDL_UnlockSurface(src);
654  }
655  return -1;
656  }
657 
658  SDL_GetSurfaceBlendMode(src, &blendmode);
659  SDL_GetSurfaceAlphaMod(src, &alphaMod);
660  SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod);
661 
662  /* SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted. */
663  if (src->format->BitsPerPixel != 32 || SDL_PIXELLAYOUT(src->format->format) != SDL_PACKEDLAYOUT_8888 || !src->format->Amask) {
664  blitRequired = SDL_TRUE;
665  }
666 
667  /* If scaling and cropping is necessary, it has to be taken care of before the rotation. */
668  if (!(srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0)) {
669  blitRequired = SDL_TRUE;
670  }
671 
672  /* The color and alpha modulation has to be applied before the rotation when using the NONE and MOD blend modes. */
673  if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD) && (alphaMod & rMod & gMod & bMod) != 255) {
674  applyModulation = SDL_TRUE;
675  SDL_SetSurfaceAlphaMod(src_clone, alphaMod);
676  SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod);
677  }
678 
679  /* Opaque surfaces are much easier to handle with the NONE blend mode. */
680  if (blendmode == SDL_BLENDMODE_NONE && !src->format->Amask && alphaMod == 255) {
681  isOpaque = SDL_TRUE;
682  }
683 
684  /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used
685  * to clear the pixels in the destination surface. The other steps are explained below.
686  */
687  if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) {
688  mask = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32,
689  0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
690  if (mask == NULL) {
691  retval = -1;
692  } else {
694  }
695  }
696 
697  /* Create a new surface should there be a format mismatch or if scaling, cropping,
698  * or modulation is required. It's possible to use the source surface directly otherwise.
699  */
700  if (!retval && (blitRequired || applyModulation)) {
701  SDL_Rect scale_rect = tmp_rect;
702  src_scaled = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32,
703  0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
704  if (src_scaled == NULL) {
705  retval = -1;
706  } else {
708  retval = SDL_BlitScaled(src_clone, srcrect, src_scaled, &scale_rect);
709  SDL_FreeSurface(src_clone);
710  src_clone = src_scaled;
711  src_scaled = NULL;
712  }
713  }
714 
715  /* SDLgfx_rotateSurface is going to make decisions depending on the blend mode. */
716  SDL_SetSurfaceBlendMode(src_clone, blendmode);
717 
718  if (!retval) {
719  SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle);
720  src_rotated = SDLgfx_rotateSurface(src_clone, angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle);
721  if (src_rotated == NULL) {
722  retval = -1;
723  }
724  if (!retval && mask != NULL) {
725  /* The mask needed for the NONE blend mode gets rotated with the same parameters. */
726  mask_rotated = SDLgfx_rotateSurface(mask, angle, dstwidth/2, dstheight/2, SDL_FALSE, 0, 0, dstwidth, dstheight, cangle, sangle);
727  if (mask_rotated == NULL) {
728  retval = -1;
729  }
730  }
731  if (!retval) {
732  /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
733  abscenterx = final_rect.x + (int)center->x;
734  abscentery = final_rect.y + (int)center->y;
735  /* Compensate the angle inversion to match the behaviour of the other backends */
736  sangle = -sangle;
737 
738  /* Top Left */
739  px = final_rect.x - abscenterx;
740  py = final_rect.y - abscentery;
741  p1x = px * cangle - py * sangle + abscenterx;
742  p1y = px * sangle + py * cangle + abscentery;
743 
744  /* Top Right */
745  px = final_rect.x + final_rect.w - abscenterx;
746  py = final_rect.y - abscentery;
747  p2x = px * cangle - py * sangle + abscenterx;
748  p2y = px * sangle + py * cangle + abscentery;
749 
750  /* Bottom Left */
751  px = final_rect.x - abscenterx;
752  py = final_rect.y + final_rect.h - abscentery;
753  p3x = px * cangle - py * sangle + abscenterx;
754  p3y = px * sangle + py * cangle + abscentery;
755 
756  /* Bottom Right */
757  px = final_rect.x + final_rect.w - abscenterx;
758  py = final_rect.y + final_rect.h - abscentery;
759  p4x = px * cangle - py * sangle + abscenterx;
760  p4y = px * sangle + py * cangle + abscentery;
761 
762  tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x));
763  tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y));
764  tmp_rect.w = dstwidth;
765  tmp_rect.h = dstheight;
766 
767  /* The NONE blend mode needs some special care with non-opaque surfaces.
768  * Other blend modes or opaque surfaces can be blitted directly.
769  */
770  if (blendmode != SDL_BLENDMODE_NONE || isOpaque) {
771  if (applyModulation == SDL_FALSE) {
772  /* If the modulation wasn't already applied, make it happen now. */
773  SDL_SetSurfaceAlphaMod(src_rotated, alphaMod);
774  SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod);
775  }
776  retval = SDL_BlitSurface(src_rotated, NULL, surface, &tmp_rect);
777  } else {
778  /* The NONE blend mode requires three steps to get the pixels onto the destination surface.
779  * First, the area where the rotated pixels will be blitted to get set to zero.
780  * This is accomplished by simply blitting a mask with the NONE blend mode.
781  * The colorkey set by the rotate function will discard the correct pixels.
782  */
783  SDL_Rect mask_rect = tmp_rect;
785  retval = SDL_BlitSurface(mask_rotated, NULL, surface, &mask_rect);
786  if (!retval) {
787  /* The next step copies the alpha value. This is done with the BLEND blend mode and
788  * by modulating the source colors with 0. Since the destination is all zeros, this
789  * will effectively set the destination alpha to the source alpha.
790  */
791  SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0);
792  mask_rect = tmp_rect;
793  retval = SDL_BlitSurface(src_rotated, NULL, surface, &mask_rect);
794  if (!retval) {
795  /* The last step gets the color values in place. The ADD blend mode simply adds them to
796  * the destination (where the color values are all zero). However, because the ADD blend
797  * mode modulates the colors with the alpha channel, a surface without an alpha mask needs
798  * to be created. This makes all source pixels opaque and the colors get copied correctly.
799  */
800  SDL_Surface *src_rotated_rgb;
801  src_rotated_rgb = SDL_CreateRGBSurfaceFrom(src_rotated->pixels, src_rotated->w, src_rotated->h,
802  src_rotated->format->BitsPerPixel, src_rotated->pitch,
803  src_rotated->format->Rmask, src_rotated->format->Gmask,
804  src_rotated->format->Bmask, 0);
805  if (src_rotated_rgb == NULL) {
806  retval = -1;
807  } else {
808  SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD);
809  retval = SDL_BlitSurface(src_rotated_rgb, NULL, surface, &tmp_rect);
810  SDL_FreeSurface(src_rotated_rgb);
811  }
812  }
813  }
814  SDL_FreeSurface(mask_rotated);
815  }
816  if (src_rotated != NULL) {
817  SDL_FreeSurface(src_rotated);
818  }
819  }
820  }
821 
822  if (SDL_MUSTLOCK(src)) {
823  SDL_UnlockSurface(src);
824  }
825  if (mask != NULL) {
827  }
828  if (src_clone != NULL) {
829  SDL_FreeSurface(src_clone);
830  }
831  return retval;
832 }
833 
834 static int
836  Uint32 format, void * pixels, int pitch)
837 {
839  Uint32 src_format;
840  void *src_pixels;
841 
842  if (!surface) {
843  return -1;
844  }
845 
846  /* NOTE: The rect is already adjusted according to the viewport by
847  * SDL_RenderReadPixels.
848  */
849 
850  if (rect->x < 0 || rect->x+rect->w > surface->w ||
851  rect->y < 0 || rect->y+rect->h > surface->h) {
852  return SDL_SetError("Tried to read outside of surface bounds");
853  }
854 
855  src_format = surface->format->format;
856  src_pixels = (void*)((Uint8 *) surface->pixels +
857  rect->y * surface->pitch +
858  rect->x * surface->format->BytesPerPixel);
859 
860  return SDL_ConvertPixels(rect->w, rect->h,
861  src_format, src_pixels, surface->pitch,
862  format, pixels, pitch);
863 }
864 
865 static void
867 {
868  SDL_Window *window = renderer->window;
869 
870  if (window) {
871  SDL_UpdateWindowSurface(window);
872  }
873 }
874 
875 static void
877 {
878  SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
879 
880  SDL_FreeSurface(surface);
881 }
882 
883 static void
885 {
886  SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
887 
888  SDL_free(data);
889  SDL_free(renderer);
890 }
891 
892 #endif /* !SDL_RENDER_DISABLED */
893 
894 /* vi: set ts=4 sw=4 expandtab: */
static int SW_SetTextureAlphaMod(SDL_Renderer *renderer, SDL_Texture *texture)
int(* RenderDrawLines)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
SDL_BlendMode blendMode
Definition: SDL_sysrender.h:57
#define SDL_SetClipRect
int(* RenderDrawPoints)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
Definition: SDL_sysrender.h:98
int SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color)
Definition: SDL_drawline.c:166
static int SW_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
#define SDL_UnlockSurface
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
static int SW_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
SDL_RendererInfo info
GLenum GLenum dst
#define SDL_PIXELLAYOUT(X)
Definition: SDL_pixels.h:126
#define SDL_MapRGBA
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
static int SW_UpdateViewport(SDL_Renderer *renderer)
SDL_BlendMode
The blend mode used in SDL_RenderCopy() and drawing operations.
Definition: SDL_blendmode.h:40
Uint8 BytesPerPixel
Definition: SDL_pixels.h:320
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
SDL_Rect rect
Definition: testrelative.c:27
#define SDL_HINT_RENDER_SCALE_QUALITY
A variable controlling the scaling quality.
Definition: SDL_hints.h:143
GLfloat GLfloat GLfloat GLfloat h
#define SDL_FillRects
void * driverdata
EGLSurface surface
Definition: eglext.h:248
The structure that defines a point.
Definition: SDL_rect.h:48
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
static int SW_SetTextureColorMod(SDL_Renderer *renderer, SDL_Texture *texture)
#define SDL_GetHint
static int SW_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
#define SDL_BlitSurface
Definition: SDL_surface.h:476
static int SW_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
int(* RenderFillRects)(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
SDL_Rect clip_rect
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_strcasecmp
GLenum src
#define SDL_IntersectRect
static int SW_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
static int SW_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
SDL_Window * window
SDL_RendererInfo info
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
#define SDL_CreateRGBSurfaceFrom
int(* RenderClear)(SDL_Renderer *renderer)
void(* DestroyRenderer)(SDL_Renderer *renderer)
GLfixed GLfixed GLint GLint GLfixed points
int(* GetOutputSize)(SDL_Renderer *renderer, int *w, int *h)
Definition: SDL_sysrender.h:81
int(* SetTextureBlendMode)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:88
#define SDL_BlitScaled
Definition: SDL_surface.h:505
#define SDL_GetSurfaceBlendMode
SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface *surface)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
int(* UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
Definition: SDL_sysrender.h:90
int x
Definition: SDL_rect.h:50
#define SDL_UpdateWindowSurface
int SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
SDL_bool retval
static int SW_SetTextureBlendMode(SDL_Renderer *renderer, SDL_Texture *texture)
int(* SetTextureColorMod)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:84
#define SDL_memcpy
GLenum GLenum GLuint texture
SDL_RenderDriver SW_RenderDriver
Definition: SDL_render_sw.c:78
SDL_Surface * surface
static void SW_RenderPresent(SDL_Renderer *renderer)
int y
Definition: SDL_rect.h:51
static void SW_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
void * pixels
Definition: SDL_surface.h:75
static int GetScaleQuality(void)
#define SDL_FreeSurface
static SDL_Renderer * renderer
#define SDL_SetSurfaceColorMod
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
struct _cl_event * event
Uint8 BitsPerPixel
Definition: SDL_pixels.h:319
SDL_BlendMode blendMode
static SDL_Surface * SW_ActivateRenderer(SDL_Renderer *renderer)
static int SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
GLenum GLint GLuint mask
static int SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
GLubyte GLubyte GLubyte GLubyte w
static int SW_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
static void SW_DestroyRenderer(SDL_Renderer *renderer)
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
#define SDL_GetWindowSurface
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
#define SDL_PixelFormatEnumToMasks
int x
Definition: SDL_rect.h:66
int(* SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* UpdateViewport)(SDL_Renderer *renderer)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: SDL_opengl.h:1572
static int SW_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
int w
Definition: SDL_rect.h:67
#define SDL_GetSurfaceAlphaMod
static int SW_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
SDL_RendererFlip
Flip constants for SDL_RenderCopyEx.
Definition: SDL_render.h:111
SDL_Rect clip_rect
Definition: SDL_surface.h:85
#define SDL_SetSurfaceRLE
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
int(* RenderCopy)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
Window state change event data (event.window.*)
Definition: SDL_events.h:174
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
static int SW_RenderClear(SDL_Renderer *renderer)
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_SetError
#define SDL_LockSurface
SDL_Surface * window
GLbitfield flags
int SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color)
Definition: SDL_drawpoint.c:65
int(* RenderCopyEx)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
#define SDL_calloc
#define SDL_CreateRGBSurface
#define SDL_GetSurfaceColorMod
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
#define SDL_MUSTLOCK(S)
Definition: SDL_surface.h:61
SDL_Rect viewport
int h
Definition: SDL_rect.h:67
int(* SetTextureAlphaMod)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:86
#define SDL_SetSurfaceBlendMode
The type used to identify a window.
Definition: SDL_sysvideo.h:73
static void SW_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
#define SDL_FillRect
GLuint color
static void SW_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
void(* WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event)
Definition: SDL_sysrender.h:80
GLfloat angle
Uint32 format
Definition: SDL_sysrender.h:52
static SDL_Renderer * SW_CreateRenderer(SDL_Window *window, Uint32 flags)
void * driverdata
Definition: SDL_sysrender.h:69
static int SW_UpdateClipRect(SDL_Renderer *renderer)
#define SDL_ConvertPixels
void(* DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:83
void(* RenderPresent)(SDL_Renderer *renderer)
EGLSurface EGLint * rects
Definition: eglext.h:282
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
GLuint GLsizei GLsizei * length
SDL_Surface * SDLgfx_rotateSurface(SDL_Surface *src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle)
Definition: SDL_rotate.c:413
int(* UpdateClipRect)(SDL_Renderer *renderer)
int SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle)
Definition: SDL_rotate.c:104
GLenum GLenum void * row
int y
Definition: SDL_rect.h:66
#define SDL_SetSurfaceAlphaMod
SDL_bool clipping_enabled
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
#define MIN(a, b)
Definition: SDL_rotate.h:23