This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_stretch.c
325 lines (296 loc) · 8.46 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* This a stretch blit implementation based on ideas given to me by
Tomasz Cejner - thanks! :)
April 27, 2000 - Sam Lantinga
*/
#include "SDL_video.h"
#include "SDL_blit.h"
/* This isn't ready for general consumption yet - it should be folded
into the general blitting mechanism.
*/
37
#if ((defined(_MFC_VER) && defined(_M_IX86)/* && !defined(_WIN32_WCE) still needed? */) || \
38
defined(__WATCOMC__) || \
39
(defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES
40
41
42
43
44
#define USE_ASM_STRETCH
#endif
#ifdef USE_ASM_STRETCH
45
#if defined(_M_IX86) || defined(i386)
46
47
48
49
50
51
52
53
54
55
56
57
#define PREFIX16 0x66
#define STORE_BYTE 0xAA
#define STORE_WORD 0xAB
#define LOAD_BYTE 0xAC
#define LOAD_WORD 0xAD
#define RETURN 0xC3
#else
#error Need assembly opcodes for this architecture
#endif
static unsigned char copy_row[4096];
58
static int
59
generate_rowbytes(int src_w, int dst_w, int bpp)
60
{
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
static struct
{
int bpp;
int src_w;
int dst_w;
} last;
int i;
int pos, inc;
unsigned char *eip;
unsigned char load, store;
/* See if we need to regenerate the copy buffer */
if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) {
return (0);
}
last.bpp = bpp;
last.src_w = src_w;
last.dst_w = dst_w;
switch (bpp) {
case 1:
load = LOAD_BYTE;
store = STORE_BYTE;
break;
case 2:
case 4:
load = LOAD_WORD;
store = STORE_WORD;
break;
default:
92
SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
return (-1);
}
pos = 0x10000;
inc = (src_w << 16) / dst_w;
eip = copy_row;
for (i = 0; i < dst_w; ++i) {
while (pos >= 0x10000L) {
if (bpp == 2) {
*eip++ = PREFIX16;
}
*eip++ = load;
pos -= 0x10000L;
}
if (bpp == 2) {
*eip++ = PREFIX16;
}
*eip++ = store;
pos += inc;
}
*eip++ = RETURN;
/* Verify that we didn't overflow (too late) */
115
116
if (eip > (copy_row + sizeof(copy_row))) {
SDL_SetError("Copy buffer overflow");
117
118
119
return (-1);
}
return (0);
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
}
#else
#define DEFINE_COPY_ROW(name, type) \
void name(type *src, int src_w, type *dst, int dst_w) \
{ \
int i; \
int pos, inc; \
type pixel = 0; \
\
pos = 0x10000; \
inc = (src_w << 16) / dst_w; \
for ( i=dst_w; i>0; --i ) { \
while ( pos >= 0x10000L ) { \
pixel = *src++; \
pos -= 0x10000L; \
} \
*dst++ = pixel; \
pos += inc; \
} \
}
142
143
DEFINE_COPY_ROW(copy_row1, Uint8)
DEFINE_COPY_ROW(copy_row2, Uint16) DEFINE_COPY_ROW(copy_row4, Uint32)
144
145
#endif /* USE_ASM_STRETCH */
/* The ASM code doesn't handle 24-bpp stretch blits */
146
void
147
copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
148
{
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
int i;
int pos, inc;
Uint8 pixel[3];
pos = 0x10000;
inc = (src_w << 16) / dst_w;
for (i = dst_w; i > 0; --i) {
while (pos >= 0x10000L) {
pixel[0] = *src++;
pixel[1] = *src++;
pixel[2] = *src++;
pos -= 0x10000L;
}
*dst++ = pixel[0];
*dst++ = pixel[1];
*dst++ = pixel[2];
pos += inc;
}
167
168
169
170
171
}
/* Perform a stretch blit between two surfaces of the same format.
NOTE: This function is not safe to call from multiple threads!
*/
172
int
173
174
SDL_SoftStretch(SDL_Surface * src, SDL_Rect * srcrect,
SDL_Surface * dst, SDL_Rect * dstrect)
175
{
176
177
178
179
180
181
182
183
184
185
int src_locked;
int dst_locked;
int pos, inc;
int dst_width;
int dst_maxrow;
int src_row, dst_row;
Uint8 *srcp = NULL;
Uint8 *dstp;
SDL_Rect full_src;
SDL_Rect full_dst;
186
#if defined(USE_ASM_STRETCH) && defined(__GNUC__)
187
int u1, u2;
188
#endif
189
190
191
const int bpp = dst->format->BytesPerPixel;
if (src->format->BitsPerPixel != dst->format->BitsPerPixel) {
192
SDL_SetError("Only works with same format surfaces");
193
194
195
196
197
198
199
200
return (-1);
}
/* Verify the blit rectangles */
if (srcrect) {
if ((srcrect->x < 0) || (srcrect->y < 0) ||
((srcrect->x + srcrect->w) > src->w) ||
((srcrect->y + srcrect->h) > src->h)) {
201
SDL_SetError("Invalid source blit rectangle");
202
203
204
205
206
207
208
209
210
211
212
213
214
return (-1);
}
} else {
full_src.x = 0;
full_src.y = 0;
full_src.w = src->w;
full_src.h = src->h;
srcrect = &full_src;
}
if (dstrect) {
if ((dstrect->x < 0) || (dstrect->y < 0) ||
((dstrect->x + dstrect->w) > dst->w) ||
((dstrect->y + dstrect->h) > dst->h)) {
215
SDL_SetError("Invalid destination blit rectangle");
216
217
218
219
220
221
222
223
224
225
226
227
return (-1);
}
} else {
full_dst.x = 0;
full_dst.y = 0;
full_dst.w = dst->w;
full_dst.h = dst->h;
dstrect = &full_dst;
}
/* Lock the destination if it's in hardware */
dst_locked = 0;
228
229
230
if (SDL_MUSTLOCK(dst)) {
if (SDL_LockSurface(dst) < 0) {
SDL_SetError("Unable to lock destination surface");
231
232
233
234
235
236
return (-1);
}
dst_locked = 1;
}
/* Lock the source if it's in hardware */
src_locked = 0;
237
238
if (SDL_MUSTLOCK(src)) {
if (SDL_LockSurface(src) < 0) {
239
if (dst_locked) {
240
SDL_UnlockSurface(dst);
241
}
242
SDL_SetError("Unable to lock source surface");
243
244
245
246
247
248
249
250
251
252
253
return (-1);
}
src_locked = 1;
}
/* Set up the data... */
pos = 0x10000;
inc = (srcrect->h << 16) / dstrect->h;
src_row = srcrect->y;
dst_row = dstrect->y;
dst_width = dstrect->w * bpp;
254
255
#ifdef USE_ASM_STRETCH
256
/* Write the opcodes for this stretch */
257
if ((bpp != 3) && (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
258
259
return (-1);
}
260
261
#endif
262
263
264
265
266
267
268
269
270
271
/* Perform the stretch blit */
for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
dstp = (Uint8 *) dst->pixels + (dst_row * dst->pitch)
+ (dstrect->x * bpp);
while (pos >= 0x10000L) {
srcp = (Uint8 *) src->pixels + (src_row * src->pitch)
+ (srcrect->x * bpp);
++src_row;
pos -= 0x10000L;
}
272
#ifdef USE_ASM_STRETCH
273
274
switch (bpp) {
case 3:
275
copy_row3(srcp, srcrect->w, dstp, dstrect->w);
276
277
break;
default:
278
#ifdef __GNUC__
279
__asm__ __volatile__("call *%4": "=&D"(u1), "=&S"(u2): "0"(dstp), "1"(srcp), "r"(copy_row):"memory");
280
#elif defined(_MSC_VER) || defined(__WATCOMC__)
281
282
283
284
285
286
287
288
{
void *code = copy_row;
__asm {
push edi
push esi
mov edi, dstp
mov esi, srcp call dword ptr code pop esi pop edi}
}
289
290
291
#else
#error Need inline assembly for this compiler
#endif
292
293
break;
}
294
#else
295
296
switch (bpp) {
case 1:
297
copy_row1(srcp, srcrect->w, dstp, dstrect->w);
298
299
break;
case 2:
300
301
copy_row2((Uint16 *) srcp, srcrect->w,
(Uint16 *) dstp, dstrect->w);
302
303
break;
case 3:
304
copy_row3(srcp, srcrect->w, dstp, dstrect->w);
305
306
break;
case 4:
307
308
copy_row4((Uint32 *) srcp, srcrect->w,
(Uint32 *) dstp, dstrect->w);
309
310
break;
}
311
#endif
312
313
314
315
316
pos += inc;
}
/* We need to unlock the surfaces if they're locked */
if (dst_locked) {
317
SDL_UnlockSurface(dst);
318
319
}
if (src_locked) {
320
SDL_UnlockSurface(src);
321
322
}
return (0);
323
324
}
325
/* vi: set ts=4 sw=4 expandtab: */