Commit c18a2c360e3100bbd71162cf922dcd8c429a8b71
Committed by
Anthony Liguori
1 parent
14899cdf
sdl zooming
Hi all, this patch implements zooming capabilities for the sdl interface. A new sdl_zoom_blit function is added that is able to scale and blit a portion of a surface into another. This way we can enable SDL_RESIZABLE and have a real_screen surface with a different size than the guest surface and let sdl_zoom_blit take care of the problem. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
6 changed files
with
413 additions
and
19 deletions
Makefile
@@ -165,7 +165,7 @@ OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) | @@ -165,7 +165,7 @@ OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) | ||
165 | 165 | ||
166 | OBJS+=keymaps.o | 166 | OBJS+=keymaps.o |
167 | ifdef CONFIG_SDL | 167 | ifdef CONFIG_SDL |
168 | -OBJS+=sdl.o x_keymap.o | 168 | +OBJS+=sdl.o sdl_zoom.o x_keymap.o |
169 | endif | 169 | endif |
170 | ifdef CONFIG_CURSES | 170 | ifdef CONFIG_CURSES |
171 | OBJS+=curses.o | 171 | OBJS+=curses.o |
@@ -209,7 +209,9 @@ cocoa.o: cocoa.m | @@ -209,7 +209,9 @@ cocoa.o: cocoa.m | ||
209 | 209 | ||
210 | keymaps.o: keymaps.c keymaps.h | 210 | keymaps.o: keymaps.c keymaps.h |
211 | 211 | ||
212 | -sdl.o: sdl.c keymaps.h sdl_keysym.h | 212 | +sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h |
213 | + | ||
214 | +sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h | ||
213 | 215 | ||
214 | sdl.o audio/sdlaudio.o baum.o: CFLAGS += $(SDL_CFLAGS) | 216 | sdl.o audio/sdlaudio.o baum.o: CFLAGS += $(SDL_CFLAGS) |
215 | 217 |
console.h
@@ -75,6 +75,7 @@ void kbd_put_keysym(int keysym); | @@ -75,6 +75,7 @@ void kbd_put_keysym(int keysym); | ||
75 | 75 | ||
76 | #define QEMU_BIG_ENDIAN_FLAG 0x01 | 76 | #define QEMU_BIG_ENDIAN_FLAG 0x01 |
77 | #define QEMU_ALLOCATED_FLAG 0x02 | 77 | #define QEMU_ALLOCATED_FLAG 0x02 |
78 | +#define QEMU_REALPIXELS_FLAG 0x04 | ||
78 | 79 | ||
79 | struct PixelFormat { | 80 | struct PixelFormat { |
80 | uint8_t bits_per_pixel; | 81 | uint8_t bits_per_pixel; |
@@ -172,7 +173,8 @@ static inline int is_surface_bgr(DisplaySurface *surface) | @@ -172,7 +173,8 @@ static inline int is_surface_bgr(DisplaySurface *surface) | ||
172 | 173 | ||
173 | static inline int is_buffer_shared(DisplaySurface *surface) | 174 | static inline int is_buffer_shared(DisplaySurface *surface) |
174 | { | 175 | { |
175 | - return (!(surface->flags & QEMU_ALLOCATED_FLAG)); | 176 | + return (!(surface->flags & QEMU_ALLOCATED_FLAG) && |
177 | + !(surface->flags & QEMU_REALPIXELS_FLAG)); | ||
176 | } | 178 | } |
177 | 179 | ||
178 | static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl) | 180 | static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl) |
sdl.c
@@ -32,6 +32,7 @@ | @@ -32,6 +32,7 @@ | ||
32 | #include "console.h" | 32 | #include "console.h" |
33 | #include "sysemu.h" | 33 | #include "sysemu.h" |
34 | #include "x_keymap.h" | 34 | #include "x_keymap.h" |
35 | +#include "sdl_zoom.h" | ||
35 | 36 | ||
36 | static DisplayChangeListener *dcl; | 37 | static DisplayChangeListener *dcl; |
37 | static SDL_Surface *real_screen; | 38 | static SDL_Surface *real_screen; |
@@ -54,20 +55,29 @@ static int guest_cursor = 0; | @@ -54,20 +55,29 @@ static int guest_cursor = 0; | ||
54 | static int guest_x, guest_y; | 55 | static int guest_x, guest_y; |
55 | static SDL_Cursor *guest_sprite = 0; | 56 | static SDL_Cursor *guest_sprite = 0; |
56 | static uint8_t allocator; | 57 | static uint8_t allocator; |
57 | -static uint8_t hostbpp; | 58 | +static SDL_PixelFormat host_format; |
59 | +static int scaling_active = 0; | ||
58 | 60 | ||
59 | static void sdl_update(DisplayState *ds, int x, int y, int w, int h) | 61 | static void sdl_update(DisplayState *ds, int x, int y, int w, int h) |
60 | { | 62 | { |
61 | // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); | 63 | // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); |
64 | + SDL_Rect rec; | ||
65 | + rec.x = x; | ||
66 | + rec.y = y; | ||
67 | + rec.w = w; | ||
68 | + rec.h = h; | ||
69 | + | ||
62 | if (guest_screen) { | 70 | if (guest_screen) { |
63 | - SDL_Rect rec; | ||
64 | - rec.x = x; | ||
65 | - rec.y = y; | ||
66 | - rec.w = w; | ||
67 | - rec.h = h; | ||
68 | - SDL_BlitSurface(guest_screen, &rec, real_screen, &rec); | ||
69 | - } | ||
70 | - SDL_UpdateRect(real_screen, x, y, w, h); | 71 | + if (!scaling_active) { |
72 | + SDL_BlitSurface(guest_screen, &rec, real_screen, &rec); | ||
73 | + } else { | ||
74 | + if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) { | ||
75 | + fprintf(stderr, "Zoom blit failed\n"); | ||
76 | + exit(1); | ||
77 | + } | ||
78 | + } | ||
79 | + } | ||
80 | + SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h); | ||
71 | } | 81 | } |
72 | 82 | ||
73 | static void sdl_setdata(DisplayState *ds) | 83 | static void sdl_setdata(DisplayState *ds) |
@@ -92,7 +102,7 @@ static void do_sdl_resize(int new_width, int new_height, int bpp) | @@ -92,7 +102,7 @@ static void do_sdl_resize(int new_width, int new_height, int bpp) | ||
92 | 102 | ||
93 | // printf("resizing to %d %d\n", w, h); | 103 | // printf("resizing to %d %d\n", w, h); |
94 | 104 | ||
95 | - flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; | 105 | + flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE; |
96 | if (gui_fullscreen) | 106 | if (gui_fullscreen) |
97 | flags |= SDL_FULLSCREEN; | 107 | flags |= SDL_FULLSCREEN; |
98 | if (gui_noframe) | 108 | if (gui_noframe) |
@@ -110,7 +120,10 @@ static void do_sdl_resize(int new_width, int new_height, int bpp) | @@ -110,7 +120,10 @@ static void do_sdl_resize(int new_width, int new_height, int bpp) | ||
110 | static void sdl_resize(DisplayState *ds) | 120 | static void sdl_resize(DisplayState *ds) |
111 | { | 121 | { |
112 | if (!allocator) { | 122 | if (!allocator) { |
113 | - do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0); | 123 | + if (!scaling_active) |
124 | + do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0); | ||
125 | + else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds)) | ||
126 | + do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds)); | ||
114 | sdl_setdata(ds); | 127 | sdl_setdata(ds); |
115 | } else { | 128 | } else { |
116 | if (guest_screen != NULL) { | 129 | if (guest_screen != NULL) { |
@@ -163,8 +176,26 @@ static DisplaySurface* sdl_create_displaysurface(int width, int height) | @@ -163,8 +176,26 @@ static DisplaySurface* sdl_create_displaysurface(int width, int height) | ||
163 | 176 | ||
164 | surface->width = width; | 177 | surface->width = width; |
165 | surface->height = height; | 178 | surface->height = height; |
179 | + | ||
180 | + if (scaling_active) { | ||
181 | + if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) { | ||
182 | + surface->linesize = width * 4; | ||
183 | + surface->pf = qemu_default_pixelformat(32); | ||
184 | + } else { | ||
185 | + surface->linesize = width * host_format.BytesPerPixel; | ||
186 | + surface->pf = sdl_to_qemu_pixelformat(&host_format); | ||
187 | + } | ||
188 | +#ifdef WORDS_BIGENDIAN | ||
189 | + surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; | ||
190 | +#else | ||
191 | + surface->flags = QEMU_ALLOCATED_FLAG; | ||
192 | +#endif | ||
193 | + surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height); | ||
194 | + | ||
195 | + return surface; | ||
196 | + } | ||
166 | 197 | ||
167 | - if (hostbpp == 16) | 198 | + if (host_format.BitsPerPixel == 16) |
168 | do_sdl_resize(width, height, 16); | 199 | do_sdl_resize(width, height, 16); |
169 | else | 200 | else |
170 | do_sdl_resize(width, height, 32); | 201 | do_sdl_resize(width, height, 32); |
@@ -174,9 +205,9 @@ static DisplaySurface* sdl_create_displaysurface(int width, int height) | @@ -174,9 +205,9 @@ static DisplaySurface* sdl_create_displaysurface(int width, int height) | ||
174 | surface->data = real_screen->pixels; | 205 | surface->data = real_screen->pixels; |
175 | 206 | ||
176 | #ifdef WORDS_BIGENDIAN | 207 | #ifdef WORDS_BIGENDIAN |
177 | - surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; | 208 | + surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG; |
178 | #else | 209 | #else |
179 | - surface->flags = QEMU_ALLOCATED_FLAG; | 210 | + surface->flags = QEMU_REALPIXELS_FLAG; |
180 | #endif | 211 | #endif |
181 | allocator = 1; | 212 | allocator = 1; |
182 | 213 | ||
@@ -188,6 +219,9 @@ static void sdl_free_displaysurface(DisplaySurface *surface) | @@ -188,6 +219,9 @@ static void sdl_free_displaysurface(DisplaySurface *surface) | ||
188 | allocator = 0; | 219 | allocator = 0; |
189 | if (surface == NULL) | 220 | if (surface == NULL) |
190 | return; | 221 | return; |
222 | + | ||
223 | + if (surface->flags & QEMU_ALLOCATED_FLAG) | ||
224 | + qemu_free(surface->data); | ||
191 | qemu_free(surface); | 225 | qemu_free(surface); |
192 | } | 226 | } |
193 | 227 | ||
@@ -482,8 +516,8 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state | @@ -482,8 +516,8 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state | ||
482 | static void toggle_full_screen(DisplayState *ds) | 516 | static void toggle_full_screen(DisplayState *ds) |
483 | { | 517 | { |
484 | gui_fullscreen = !gui_fullscreen; | 518 | gui_fullscreen = !gui_fullscreen; |
485 | - do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel); | ||
486 | if (gui_fullscreen) { | 519 | if (gui_fullscreen) { |
520 | + scaling_active = 0; | ||
487 | gui_saved_grab = gui_grab; | 521 | gui_saved_grab = gui_grab; |
488 | sdl_grab_start(); | 522 | sdl_grab_start(); |
489 | } else { | 523 | } else { |
@@ -675,6 +709,18 @@ static void sdl_refresh(DisplayState *ds) | @@ -675,6 +709,18 @@ static void sdl_refresh(DisplayState *ds) | ||
675 | } | 709 | } |
676 | } | 710 | } |
677 | break; | 711 | break; |
712 | + case SDL_VIDEORESIZE: | ||
713 | + { | ||
714 | + SDL_ResizeEvent *rev = &ev->resize; | ||
715 | + int bpp = real_screen->format->BitsPerPixel; | ||
716 | + if (bpp != 16 && bpp != 32) | ||
717 | + bpp = 32; | ||
718 | + do_sdl_resize(rev->w, rev->h, bpp); | ||
719 | + scaling_active = 1; | ||
720 | + vga_hw_invalidate(); | ||
721 | + vga_hw_update(); | ||
722 | + break; | ||
723 | + } | ||
678 | default: | 724 | default: |
679 | break; | 725 | break; |
680 | } | 726 | } |
@@ -783,7 +829,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) | @@ -783,7 +829,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) | ||
783 | exit(1); | 829 | exit(1); |
784 | } | 830 | } |
785 | vi = SDL_GetVideoInfo(); | 831 | vi = SDL_GetVideoInfo(); |
786 | - hostbpp = vi->vfmt->BitsPerPixel; | 832 | + host_format = *(vi->vfmt); |
787 | 833 | ||
788 | dcl = qemu_mallocz(sizeof(DisplayChangeListener)); | 834 | dcl = qemu_mallocz(sizeof(DisplayChangeListener)); |
789 | dcl->dpy_update = sdl_update; | 835 | dcl->dpy_update = sdl_update; |
sdl_zoom.c
0 โ 100644
1 | +/* | ||
2 | + * SDL_zoom - surface scaling | ||
3 | + * | ||
4 | + * Copyright (c) 2009 Citrix Systems, Inc. | ||
5 | + * | ||
6 | + * Derived from: SDL_rotozoom, LGPL (c) A. Schiffler from the SDL_gfx library. | ||
7 | + * Modifications by Stefano Stabellini. | ||
8 | + * | ||
9 | + * This work is licensed under the terms of the GNU GPL version 2. | ||
10 | + * See the COPYING file in the top-level directory. | ||
11 | + * | ||
12 | + */ | ||
13 | + | ||
14 | +#include "sdl_zoom.h" | ||
15 | +#include "osdep.h" | ||
16 | +#include <stdint.h> | ||
17 | + | ||
18 | +static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth, | ||
19 | + SDL_Rect *dst_rect); | ||
20 | +static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth, | ||
21 | + SDL_Rect *dst_rect); | ||
22 | + | ||
23 | +#define BPP 32 | ||
24 | +#include "sdl_zoom_template.h" | ||
25 | +#undef BPP | ||
26 | +#define BPP 16 | ||
27 | +#include "sdl_zoom_template.h" | ||
28 | +#undef BPP | ||
29 | + | ||
30 | +int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, int smooth, | ||
31 | + SDL_Rect *in_rect) | ||
32 | +{ | ||
33 | + SDL_Rect zoom, src_rect; | ||
34 | + int extra; | ||
35 | + | ||
36 | + /* Grow the size of the modified rectangle to avoid edge artefacts */ | ||
37 | + src_rect.x = (in_rect->x > 0) ? (in_rect->x - 1) : 0; | ||
38 | + src_rect.y = (in_rect->y > 0) ? (in_rect->y - 1) : 0; | ||
39 | + | ||
40 | + src_rect.w = in_rect->w + 1; | ||
41 | + if (src_rect.x + src_rect.w > src_sfc->w) | ||
42 | + src_rect.w = src_sfc->w - src_rect.x; | ||
43 | + | ||
44 | + src_rect.h = in_rect->h + 1; | ||
45 | + if (src_rect.y + src_rect.h > src_sfc->h) | ||
46 | + src_rect.h = src_sfc->h - src_rect.y; | ||
47 | + | ||
48 | + /* (x,y) : round down */ | ||
49 | + zoom.x = (int)(((float)(src_rect.x * dst_sfc->w)) / (float)(src_sfc->w)); | ||
50 | + zoom.y = (int)(((float)(src_rect.y * dst_sfc->h)) / (float)(src_sfc->h)); | ||
51 | + | ||
52 | + /* (w,h) : round up */ | ||
53 | + zoom.w = (int)( ((double)((src_rect.w * dst_sfc->w) + (src_sfc->w - 1))) / | ||
54 | + (double)(src_sfc->w)); | ||
55 | + | ||
56 | + zoom.h = (int)( ((double)((src_rect.h * dst_sfc->h) + (src_sfc->h - 1))) / | ||
57 | + (double)(src_sfc->h)); | ||
58 | + | ||
59 | + /* Account for any (x,y) rounding by adding one-source-pixel's worth | ||
60 | + * of destination pixels and then edge checking. | ||
61 | + */ | ||
62 | + | ||
63 | + extra = ((dst_sfc->w-1) / src_sfc->w) + 1; | ||
64 | + | ||
65 | + if ((zoom.x + zoom.w) < (dst_sfc->w - extra)) | ||
66 | + zoom.w += extra; | ||
67 | + else | ||
68 | + zoom.w = dst_sfc->w - zoom.x; | ||
69 | + | ||
70 | + extra = ((dst_sfc->h-1) / src_sfc->h) + 1; | ||
71 | + | ||
72 | + if ((zoom.y + zoom.h) < (dst_sfc->h - extra)) | ||
73 | + zoom.h += extra; | ||
74 | + else | ||
75 | + zoom.h = dst_sfc->h - zoom.y; | ||
76 | + | ||
77 | + /* The rectangle (zoom.x, zoom.y, zoom.w, zoom.h) is the area on the | ||
78 | + * destination surface that needs to be updated. | ||
79 | + */ | ||
80 | + if (src_sfc->format->BitsPerPixel == 32) | ||
81 | + sdl_zoom_rgb32(src_sfc, dst_sfc, smooth, &zoom); | ||
82 | + else if (src_sfc->format->BitsPerPixel == 16) | ||
83 | + sdl_zoom_rgb16(src_sfc, dst_sfc, smooth, &zoom); | ||
84 | + else { | ||
85 | + fprintf(stderr, "pixel format not supported\n"); | ||
86 | + return -1; | ||
87 | + } | ||
88 | + | ||
89 | + /* Return the rectangle of the update to the caller */ | ||
90 | + *in_rect = zoom; | ||
91 | + | ||
92 | + return 0; | ||
93 | +} | ||
94 | + |
sdl_zoom.h
0 โ 100644
1 | +/* | ||
2 | + * SDL_zoom - surface scaling | ||
3 | + * | ||
4 | + * Copyright (c) 2009 Citrix Systems, Inc. | ||
5 | + * | ||
6 | + * Derived from: SDL_rotozoom, LGPL (c) A. Schiffler from the SDL_gfx library. | ||
7 | + * Modifications by Stefano Stabellini. | ||
8 | + * | ||
9 | + * This work is licensed under the terms of the GNU GPL version 2. | ||
10 | + * See the COPYING file in the top-level directory. | ||
11 | + * | ||
12 | + */ | ||
13 | + | ||
14 | +#ifndef _SDL_zoom_h | ||
15 | +#define _SDL_zoom_h | ||
16 | + | ||
17 | +#include <SDL/SDL.h> | ||
18 | + | ||
19 | +#define SMOOTHING_OFF 0 | ||
20 | +#define SMOOTHING_ON 1 | ||
21 | + | ||
22 | +int sdl_zoom_blit(SDL_Surface *src_sfc, SDL_Surface *dst_sfc, | ||
23 | + int smooth, SDL_Rect *src_rect); | ||
24 | + | ||
25 | +#endif /* _SDL_zoom_h */ |
sdl_zoom_template.h
0 โ 100644
1 | +/* | ||
2 | + * SDL_zoom_template - surface scaling | ||
3 | + * | ||
4 | + * Copyright (c) 2009 Citrix Systems, Inc. | ||
5 | + * | ||
6 | + * Derived from: SDL_rotozoom, LGPL (c) A. Schiffler from the SDL_gfx library. | ||
7 | + * Modifications by Stefano Stabellini. | ||
8 | + * | ||
9 | + * This work is licensed under the terms of the GNU GPL version 2. | ||
10 | + * See the COPYING file in the top-level directory. | ||
11 | + * | ||
12 | + */ | ||
13 | + | ||
14 | +#if BPP == 16 | ||
15 | +#define SDL_TYPE Uint16 | ||
16 | +#elif BPP == 32 | ||
17 | +#define SDL_TYPE Uint32 | ||
18 | +#else | ||
19 | +#error unsupport depth | ||
20 | +#endif | ||
21 | + | ||
22 | +/* | ||
23 | + * Simple helper functions to make the code looks nicer | ||
24 | + * | ||
25 | + * Assume spf = source SDL_PixelFormat | ||
26 | + * dpf = dest SDL_PixelFormat | ||
27 | + * | ||
28 | + */ | ||
29 | +#define getRed(color) (((color) & spf->Rmask) >> spf->Rshift) | ||
30 | +#define getGreen(color) (((color) & spf->Gmask) >> spf->Gshift) | ||
31 | +#define getBlue(color) (((color) & spf->Bmask) >> spf->Bshift) | ||
32 | +#define getAlpha(color) (((color) & spf->Amask) >> spf->Ashift) | ||
33 | + | ||
34 | +#define setRed(r, pcolor) do { \ | ||
35 | + *pcolor = ((*pcolor) & (~(dpf->Rmask))) + \ | ||
36 | + (((r) & (dpf->Rmask >> dpf->Rshift)) << dpf->Rshift); \ | ||
37 | +} while (0); | ||
38 | + | ||
39 | +#define setGreen(g, pcolor) do { \ | ||
40 | + *pcolor = ((*pcolor) & (~(dpf->Gmask))) + \ | ||
41 | + (((g) & (dpf->Gmask >> dpf->Gshift)) << dpf->Gshift); \ | ||
42 | +} while (0); | ||
43 | + | ||
44 | +#define setBlue(b, pcolor) do { \ | ||
45 | + *pcolor = ((*pcolor) & (~(dpf->Bmask))) + \ | ||
46 | + (((b) & (dpf->Bmask >> dpf->Bshift)) << dpf->Bshift); \ | ||
47 | +} while (0); | ||
48 | + | ||
49 | +#define setAlpha(a, pcolor) do { \ | ||
50 | + *pcolor = ((*pcolor) & (~(dpf->Amask))) + \ | ||
51 | + (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \ | ||
52 | +} while (0); | ||
53 | + | ||
54 | +static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth, | ||
55 | + SDL_Rect *dst_rect) | ||
56 | +{ | ||
57 | + int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, sstep_jump; | ||
58 | + SDL_TYPE *c00, *c01, *c10, *c11, *sp, *csp, *dp; | ||
59 | + int d_gap; | ||
60 | + SDL_PixelFormat *spf = src->format; | ||
61 | + SDL_PixelFormat *dpf = dst->format; | ||
62 | + | ||
63 | + if (smooth) { | ||
64 | + /* For interpolation: assume source dimension is one pixel. | ||
65 | + * Smaller here to avoid overflow on right and bottom edge. | ||
66 | + */ | ||
67 | + sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w); | ||
68 | + sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h); | ||
69 | + } else { | ||
70 | + sx = (int) (65536.0 * (float) src->w / (float) dst->w); | ||
71 | + sy = (int) (65536.0 * (float) src->h / (float) dst->h); | ||
72 | + } | ||
73 | + | ||
74 | + if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) { | ||
75 | + return (-1); | ||
76 | + } | ||
77 | + if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) { | ||
78 | + free(sax); | ||
79 | + return (-1); | ||
80 | + } | ||
81 | + | ||
82 | + sp = csp = (SDL_TYPE *) src->pixels; | ||
83 | + dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch + | ||
84 | + dst_rect->x * dst->format->BytesPerPixel); | ||
85 | + | ||
86 | + csx = 0; | ||
87 | + csax = sax; | ||
88 | + for (x = 0; x <= dst->w; x++) { | ||
89 | + *csax = csx; | ||
90 | + csax++; | ||
91 | + csx &= 0xffff; | ||
92 | + csx += sx; | ||
93 | + } | ||
94 | + csy = 0; | ||
95 | + csay = say; | ||
96 | + for (y = 0; y <= dst->h; y++) { | ||
97 | + *csay = csy; | ||
98 | + csay++; | ||
99 | + csy &= 0xffff; | ||
100 | + csy += sy; | ||
101 | + } | ||
102 | + | ||
103 | + d_gap = dst->pitch - dst_rect->w * dst->format->BytesPerPixel; | ||
104 | + | ||
105 | + if (smooth) { | ||
106 | + csay = say; | ||
107 | + for (y = 0; y < dst_rect->y; y++) { | ||
108 | + csay++; | ||
109 | + sstep = (*csay >> 16) * src->pitch; | ||
110 | + csp = (SDL_TYPE *) ((Uint8 *) csp + sstep); | ||
111 | + } | ||
112 | + | ||
113 | + /* Calculate sstep_jump */ | ||
114 | + csax = sax; | ||
115 | + sstep_jump = 0; | ||
116 | + for (x = 0; x < dst_rect->x; x++) { | ||
117 | + csax++; | ||
118 | + sstep = (*csax >> 16); | ||
119 | + sstep_jump += sstep; | ||
120 | + } | ||
121 | + | ||
122 | + for (y = 0; y < dst_rect->h ; y++) { | ||
123 | + /* Setup colour source pointers */ | ||
124 | + c00 = csp + sstep_jump; | ||
125 | + c01 = c00 + 1; | ||
126 | + c10 = (SDL_TYPE *) ((Uint8 *) csp + src->pitch) + sstep_jump; | ||
127 | + c11 = c10 + 1; | ||
128 | + csax = sax + dst_rect->x; | ||
129 | + | ||
130 | + for (x = 0; x < dst_rect->w; x++) { | ||
131 | + | ||
132 | + /* Interpolate colours */ | ||
133 | + ex = (*csax & 0xffff); | ||
134 | + ey = (*csay & 0xffff); | ||
135 | + t1 = ((((getRed(*c01) - getRed(*c00)) * ex) >> 16) + | ||
136 | + getRed(*c00)) & (dpf->Rmask >> dpf->Rshift); | ||
137 | + t2 = ((((getRed(*c11) - getRed(*c10)) * ex) >> 16) + | ||
138 | + getRed(*c10)) & (dpf->Rmask >> dpf->Rshift); | ||
139 | + setRed((((t2 - t1) * ey) >> 16) + t1, dp); | ||
140 | + t1 = ((((getGreen(*c01) - getGreen(*c00)) * ex) >> 16) + | ||
141 | + getGreen(*c00)) & (dpf->Gmask >> dpf->Gshift); | ||
142 | + t2 = ((((getGreen(*c11) - getGreen(*c10)) * ex) >> 16) + | ||
143 | + getGreen(*c10)) & (dpf->Gmask >> dpf->Gshift); | ||
144 | + setGreen((((t2 - t1) * ey) >> 16) + t1, dp); | ||
145 | + t1 = ((((getBlue(*c01) - getBlue(*c00)) * ex) >> 16) + | ||
146 | + getBlue(*c00)) & (dpf->Bmask >> dpf->Bshift); | ||
147 | + t2 = ((((getBlue(*c11) - getBlue(*c10)) * ex) >> 16) + | ||
148 | + getBlue(*c10)) & (dpf->Bmask >> dpf->Bshift); | ||
149 | + setBlue((((t2 - t1) * ey) >> 16) + t1, dp); | ||
150 | + t1 = ((((getAlpha(*c01) - getAlpha(*c00)) * ex) >> 16) + | ||
151 | + getAlpha(*c00)) & (dpf->Amask >> dpf->Ashift); | ||
152 | + t2 = ((((getAlpha(*c11) - getAlpha(*c10)) * ex) >> 16) + | ||
153 | + getAlpha(*c10)) & (dpf->Amask >> dpf->Ashift); | ||
154 | + setAlpha((((t2 - t1) * ey) >> 16) + t1, dp); | ||
155 | + | ||
156 | + /* Advance source pointers */ | ||
157 | + csax++; | ||
158 | + sstep = (*csax >> 16); | ||
159 | + c00 += sstep; | ||
160 | + c01 += sstep; | ||
161 | + c10 += sstep; | ||
162 | + c11 += sstep; | ||
163 | + /* Advance destination pointer */ | ||
164 | + dp++; | ||
165 | + } | ||
166 | + /* Advance source pointer */ | ||
167 | + csay++; | ||
168 | + csp = (SDL_TYPE *) ((Uint8 *) csp + (*csay >> 16) * src->pitch); | ||
169 | + /* Advance destination pointers */ | ||
170 | + dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap); | ||
171 | + } | ||
172 | + | ||
173 | + | ||
174 | + } else { | ||
175 | + csay = say; | ||
176 | + | ||
177 | + for (y = 0; y < dst_rect->y; y++) { | ||
178 | + csay++; | ||
179 | + sstep = (*csay >> 16) * src->pitch; | ||
180 | + csp = (SDL_TYPE *) ((Uint8 *) csp + sstep); | ||
181 | + } | ||
182 | + | ||
183 | + /* Calculate sstep_jump */ | ||
184 | + csax = sax; | ||
185 | + sstep_jump = 0; | ||
186 | + for (x = 0; x < dst_rect->x; x++) { | ||
187 | + csax++; | ||
188 | + sstep = (*csax >> 16); | ||
189 | + sstep_jump += sstep; | ||
190 | + } | ||
191 | + | ||
192 | + for (y = 0 ; y < dst_rect->h ; y++) { | ||
193 | + sp = csp + sstep_jump; | ||
194 | + csax = sax + dst_rect->x; | ||
195 | + | ||
196 | + for (x = 0; x < dst_rect->w; x++) { | ||
197 | + | ||
198 | + /* Draw */ | ||
199 | + *dp = *sp; | ||
200 | + | ||
201 | + /* Advance source pointers */ | ||
202 | + csax++; | ||
203 | + sstep = (*csax >> 16); | ||
204 | + sp += sstep; | ||
205 | + | ||
206 | + /* Advance destination pointer */ | ||
207 | + dp++; | ||
208 | + } | ||
209 | + /* Advance source pointers */ | ||
210 | + csay++; | ||
211 | + sstep = (*csay >> 16) * src->pitch; | ||
212 | + csp = (SDL_TYPE *) ((Uint8 *) csp + sstep); | ||
213 | + | ||
214 | + /* Advance destination pointer */ | ||
215 | + dp = (SDL_TYPE *) ((Uint8 *) dp + d_gap); | ||
216 | + } | ||
217 | + } | ||
218 | + | ||
219 | + free(sax); | ||
220 | + free(say); | ||
221 | + return (0); | ||
222 | +} | ||
223 | + | ||
224 | +#undef SDL_TYPE | ||
225 | + |