1 /******************************************************************************/
2 /* Mednafen - Multi-system Emulator */
3 /******************************************************************************/
4 /* nongl.cpp:
5 ** Copyright (C) 2005-2016 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "main.h"
23 #include "video.h"
24 #include "nongl.h"
25 #include "nnx.h"
26
27 //
28 // Source rectangle sanity checking(more strict than dest rectangle sanity checking). */
29 //
30 // true if it's ok, false if it's "bad" and we shouldn't blit.
CheckSourceRect(const MDFN_Surface * src_surface,const MDFN_Rect * src_rect)31 static INLINE bool CheckSourceRect(const MDFN_Surface *src_surface, const MDFN_Rect *src_rect)
32 {
33 if((src_rect->w <= 0) || (src_rect->h <= 0))
34 return(false);
35
36 if((src_rect->x < 0) || (src_rect->y < 0))
37 return(false);
38
39 if(((int64)src_rect->x + src_rect->w) > src_surface->w)
40 return(false);
41
42 if(((int64)src_rect->y + src_rect->h) > src_surface->h)
43 return(false);
44
45 return(true);
46 }
47
48 //
49 // Dest rectangle sanity checking.
50 //
CheckDestRect(const MDFN_Surface * dest_surface,const MDFN_Rect * dest_rect)51 static INLINE bool CheckDestRect(const MDFN_Surface *dest_surface, const MDFN_Rect *dest_rect)
52 {
53 if((dest_rect->w <= 0) || (dest_rect->h <= 0))
54 return(false);
55
56 if(dest_rect->x >= dest_surface->w)
57 return(false);
58
59 if(dest_rect->y >= dest_surface->h)
60 return(false);
61
62 if(((int64)dest_rect->x + dest_rect->w) <= 0)
63 return(false);
64
65 if(((int64)dest_rect->y + dest_rect->h) <= 0)
66 return(false);
67
68 return(true);
69 }
70
71 //
72 // true if blitting needs to be done with some sort of clipping, false if not.
73 //
CheckDRNeedsClipping(const MDFN_Surface * dest_surface,const MDFN_Rect * dest_rect)74 static INLINE bool CheckDRNeedsClipping(const MDFN_Surface *dest_surface, const MDFN_Rect *dest_rect)
75 {
76 if(dest_rect->x < 0 || dest_rect->y < 0)
77 return(true);
78
79 if(((int64)dest_rect->x + dest_rect->w) > dest_surface->w)
80 return(true);
81
82 if(((int64)dest_rect->y + dest_rect->h) > dest_surface->h)
83 return(true);
84
85 return(false);
86 }
87
88 #define SFTBLT_SETUP(T) \
89 /* dr_* should only be used in the actual blitting functions for ratio calculations. */ \
90 const int32 sr_w = src_rect->w; \
91 const int32 sr_h = src_rect->h; \
92 const int32 dr_w = dest_rect->w; \
93 const int32 dr_h = dest_rect->h; \
94 const int32 iter_w = std::min(std::max(0, dest_surface->w - std::max(0, dest_rect->x)), std::max(0, dr_w + std::min(0, dest_rect->x))); \
95 const int32 iter_h = std::min(std::max(0, dest_surface->h - std::max(0, dest_rect->y)), std::max(0, dr_h + std::min(0, dest_rect->y))); \
96 const uint32 src_pitchinpix = src_surface->pitchinpix; \
97 const uint32 dest_pitchinpix = dest_surface->pitchinpix; \
98 const int32 dest_pixels_fudge_x = -std::min(0, dest_rect->x); \
99 const int32 dest_pixels_fudge_y = -std::min(0, dest_rect->y); \
100 const T* src_pixels = src_surface->pixels + src_rect->x + (src_rect->y * src_pitchinpix); \
101 T* dest_pixels = dest_surface->pixels + std::max(0, dest_rect->x) + (std::max(0, dest_rect->y) * dest_pitchinpix);
102
103
104 // const int32 src_pixels_fudge_x = (int64)(-std::min(0, dest_rect->x)) * sr_w / dr_w;
105 // const int32 src_pixels_fudge_y = (int64)(-std::min(0, dest_rect->y)) * sr_h / dr_h;
106 // const T* src_pixels = src_surface->pixels + src_rect->x + src_pixels_fudge_x + ((src_rect->y + src_pixels_fudge_y) * src_pitchinpix);
107
108 // Write pixel source-alpha-eval
109 template<typename T, unsigned int alpha_shift>
WPSAE(T & back_pix_ref,const T fore_pix)110 static INLINE void WPSAE(T &back_pix_ref, const T fore_pix)
111 {
112 if(sizeof(T) == 4 && alpha_shift < 31)
113 {
114 const T back_pix = back_pix_ref;
115 const uint32 alpha = (((fore_pix >> alpha_shift) & 0xFF) * 129) >> 7; //65921) >> 16;
116 const uint32 alpha_negoo = 256 - alpha;
117 T new_pix;
118
119 new_pix = 0;
120 new_pix |= ((((back_pix & 0xFF00FF) * alpha_negoo) + ((fore_pix & 0xFF00FF) * alpha)) >> 8) & 0x00FF00FF;
121 new_pix |= (((((back_pix >> 8) & 0xFF00FF) * alpha_negoo) + (((fore_pix >> 8) & 0xFF00FF) * alpha))) & 0xFF00FF00;
122 back_pix_ref = new_pix;
123 }
124 else
125 back_pix_ref = fore_pix;
126 }
127
128 template<typename T, int alpha_shift>
BlitStraight(const MDFN_Surface * src_surface,const MDFN_Rect * src_rect,MDFN_Surface * dest_surface,const MDFN_Rect * dest_rect)129 static void BlitStraight(const MDFN_Surface *src_surface, const MDFN_Rect *src_rect, MDFN_Surface *dest_surface, const MDFN_Rect *dest_rect)
130 {
131 SFTBLT_SETUP(T);
132
133 (void)sr_w;
134 (void)sr_h;
135
136 //puts("Straight");
137
138 src_pixels += dest_pixels_fudge_x + (dest_pixels_fudge_y * src_pitchinpix);
139
140 for(int32 y = 0; y < iter_h; y++)
141 {
142 if(alpha_shift >= 0)
143 {
144 for(int32 x = 0; x < iter_w; x++)
145 {
146 WPSAE<T, alpha_shift>(dest_pixels[x], src_pixels[x]);
147 }
148 }
149 else
150 memcpy(dest_pixels, src_pixels, iter_w * sizeof(T));
151
152 src_pixels += src_pitchinpix;
153 dest_pixels += dest_pitchinpix;
154 }
155 }
156
157 template<typename T, int alpha_shift>
BlitIScale(const MDFN_Surface * src_surface,const MDFN_Rect & sr,MDFN_Surface * dest_surface,const MDFN_Rect & dr,int xscale,int yscale)158 static void BlitIScale(const MDFN_Surface *src_surface, const MDFN_Rect &sr, MDFN_Surface *dest_surface, const MDFN_Rect &dr, int xscale, int yscale)
159 {
160 //puts("IScale");
161 const uint32 src_pitchinpix = src_surface->pitchinpix;
162 int32 dpitch_diff;
163
164 T *src_row, *dest_row;
165
166 src_row = src_surface->pixels + src_surface->pitchinpix * sr.y + sr.x;
167 dest_row = dest_surface->pixels + dest_surface->pitchinpix * dr.y + dr.x;
168
169 dpitch_diff = dest_surface->pitchinpix - (sr.w * xscale);
170
171 //printf("%f %f, %d %d\n", dw_to_sw_ratio, dh_to_sh_ratio, xscale, yscale);
172
173 for(int y = sr.h; y; y--)
174 {
175 for(int ys = yscale; ys; ys--)
176 {
177 uint32 *src_pixels = src_row;
178
179 for(int x = sr.w; x; x--)
180 {
181 uint32 tmp_pixel = *src_pixels;
182
183 for(int xs = xscale; xs; xs--)
184 WPSAE<T, alpha_shift>(*dest_row++, tmp_pixel);
185
186 src_pixels++;
187 }
188 dest_row += dpitch_diff;
189 }
190 src_row += src_pitchinpix;
191 }
192 }
193
194 template<typename T, int alpha_shift, bool scanlines_on, bool rotation_on>
BlitSScale(const MDFN_Surface * src_surface,const MDFN_Rect * src_rect,MDFN_Surface * dest_surface,const MDFN_Rect * dest_rect,const MDFN_Rect * original_src_rect,int scanlines=0,unsigned rotation=0,int InterlaceField=-1)195 static void BlitSScale(const MDFN_Surface *src_surface, const MDFN_Rect *src_rect, MDFN_Surface *dest_surface, const MDFN_Rect *dest_rect, const MDFN_Rect *original_src_rect, int scanlines = 0, unsigned rotation = 0, int InterlaceField = -1)
196 {
197 SFTBLT_SETUP(T);
198
199 //puts("SScale");
200 // printf("%d %d\n", iter_w, iter_h);
201
202 static const unsigned fract_bits = 18; // 2**(32 - 18) == 16384
203
204 uint32 src_x, src_y;
205 uint32 src_x_inc, src_y_inc;
206
207 // Extra vars for scanlines
208 const int32 o_sr_h = original_src_rect->h;
209 uint32 sl_mult;
210 uint32 sl;
211 uint32 sl_inc;
212 uint32 sl_init; // For scanlines+rotation!!
213
214 // Extra vars for rotation.
215 uint32 src_x_init;
216 uint32 src_y_init;
217
218 if(rotation_on)
219 {
220 if(rotation == MDFN_ROTATE90)
221 {
222 src_x_inc = ((sr_h << fract_bits) + dr_w - 1) / dr_w;
223 src_y_inc = -((sr_w << fract_bits) + dr_h - 1) / dr_h;
224 }
225 else //if(rotated == MDFN_ROTATE270)
226 {
227 src_x_inc = -((sr_h << fract_bits) + dr_w - 1) / dr_w;
228 src_y_inc = ((sr_w << fract_bits) + dr_h - 1) / dr_h;
229 }
230
231 //
232 //
233 //
234 if((((int64)abs((int32)src_x_inc) * (iter_w + dest_pixels_fudge_x - 1)) >> fract_bits) >= sr_h)
235 {
236 printf("Rot %u Prec-round BUG X\n", rotation);
237 if((int32)src_x_inc < 0)
238 src_x_inc++;
239 else
240 src_x_inc--;
241 }
242
243 if((((int64)abs((int32)src_y_inc) * (iter_h + dest_pixels_fudge_y - 1)) >> fract_bits) >= sr_w)
244 {
245 printf("Rot %u Prec-round BUG Y\n", rotation);
246 if((int32)src_y_inc < 0)
247 src_y_inc++;
248 else
249 src_y_inc--;
250 }
251 //
252 //
253 //
254
255 if(rotation == MDFN_ROTATE90)
256 {
257 src_x_init = dest_pixels_fudge_x * src_x_inc;
258 src_y_init = (iter_h + dest_pixels_fudge_y - 1) * -src_y_inc;
259 }
260 else //if(rotated == MDFN_ROTATE270)
261 {
262 src_x_init = (iter_w + dest_pixels_fudge_x - 1) * -src_x_inc;
263 src_y_init = dest_pixels_fudge_y * src_y_inc;
264 //printf("%d %08x\n", dest_pixels_fudge_x, dest_pixels_fudge_y * src_y_inc);
265 }
266 }
267 else
268 {
269 src_x_inc = ((sr_w << fract_bits) + dr_w - 1) / dr_w;
270 src_y_inc = ((sr_h << fract_bits) + dr_h - 1) / dr_h;
271
272 if((((int64)src_x_inc * (iter_w + dest_pixels_fudge_x - 1)) >> fract_bits) >= sr_w)
273 {
274 puts("Prec-round BUG X");
275 src_x_inc--;
276 }
277
278 if((((int64)src_y_inc * (iter_h + dest_pixels_fudge_y - 1)) >> fract_bits) >= sr_h)
279 {
280 puts("Prec-round BUG Y");
281 src_y_inc--;
282 }
283
284 src_pixels += ((int64)dest_pixels_fudge_x * src_x_inc) >> fract_bits;
285 src_pixels += (((int64)dest_pixels_fudge_y * src_y_inc) >> fract_bits) * src_pitchinpix;
286 }
287
288 #if 0
289 printf("%lld, %lld\n", ((long long)src_y + src_y_inc * (dr.h - 1)) >> fract_bits, ((long long)src_y + src_y_inc * (dr.h - (dr.h / sr.h) - 1)) >> fract_bits);
290 #endif
291
292 if(scanlines_on)
293 {
294 unsigned o_sr_h_ps = 0;
295 int sl_init_offs = 0;
296
297 sl_mult = 256 - 256 * abs(scanlines) / 100;
298
299 if((scanlines < 0 || (dest_rect->h == original_src_rect->h)) && InterlaceField >= 0)
300 {
301 o_sr_h_ps = 1;
302 sl_init_offs = InterlaceField;
303 }
304
305 if(rotation_on)
306 {
307 if(rotation == MDFN_ROTATE90)
308 {
309 sl_inc = (((o_sr_h >> o_sr_h_ps) << fract_bits) + dr_w - 1) / dr_w * 2;
310 sl_init = (sl_init_offs * (dr_w / o_sr_h) + dest_pixels_fudge_x) * sl_inc;
311 }
312 else
313 {
314 sl_inc = -(((o_sr_h >> o_sr_h_ps) << fract_bits) + dr_w - 1) / dr_w * 2;
315 sl_init = (sl_init_offs * (dr_w / o_sr_h) + iter_w + dest_pixels_fudge_x - 1) * -sl_inc;
316 }
317 }
318 else
319 {
320 sl_inc = (((o_sr_h >> o_sr_h_ps) << fract_bits) + dr_h - 1) / dr_h * 2;
321 sl_init = (sl_init_offs * (dr_h / o_sr_h)) * sl_inc;
322 }
323
324 if(!rotation_on)
325 sl = sl_init;
326 //printf("%08x, %d\n", sl_init, sl_init >> fract_bits);
327 }
328
329 if(rotation_on)
330 src_y = src_y_init;
331 else
332 src_y = 0;
333
334 for(int y = 0; y < iter_h; y++)
335 {
336 T *dest_row_ptr = dest_pixels + (y * dest_pitchinpix);
337 const T *src_row_ptr;
338 const T *src_col_ptr;
339
340 if(rotation_on)
341 {
342 src_x = src_x_init;
343 src_col_ptr = src_pixels + (src_y >> fract_bits);
344 if(scanlines_on)
345 sl = sl_init;
346 }
347 else
348 {
349 src_x = 0;
350 src_row_ptr = src_pixels + (src_y >> fract_bits) * src_pitchinpix;
351 }
352
353 if(scanlines_on && (rotation_on || (sl & (1U << fract_bits))))
354 {
355 for(int x = 0; x < iter_w; x++)
356 {
357 T pixel = rotation_on ? src_col_ptr[(src_x >> fract_bits) * src_pitchinpix] : src_row_ptr[(src_x >> fract_bits)];
358
359 if(!rotation_on || (sl & (1U << fract_bits)))
360 pixel = ((((pixel & 0xFF00FF) * sl_mult) >> 8) & 0x00FF00FF) | ((((pixel >> 8) & 0xFF00FF) * sl_mult) & 0xFF00FF00);
361
362 WPSAE<T, alpha_shift>(dest_row_ptr[x], pixel);
363 src_x += src_x_inc;
364 if(rotation_on)
365 sl += sl_inc;
366 }
367 }
368 else
369 {
370 for(int x = 0; x < iter_w; x++)
371 {
372 T pixel = rotation_on ? src_col_ptr[(src_x >> fract_bits) * src_pitchinpix] : src_row_ptr[(src_x >> fract_bits)];
373
374 WPSAE<T, alpha_shift>(dest_row_ptr[x], pixel);
375 src_x += src_x_inc;
376 }
377 }
378
379 src_y += src_y_inc;
380 if(scanlines_on && !rotation_on)
381 sl += sl_inc;
382 }
383 }
384
MDFN_StretchBlitSurface(const MDFN_Surface * src_surface,const MDFN_Rect & src_rect,MDFN_Surface * dest_surface,const MDFN_Rect & dest_rect,bool source_alpha,int scanlines,const MDFN_Rect * original_src_rect,int rotated,int InterlaceField)385 void MDFN_StretchBlitSurface(const MDFN_Surface* src_surface, const MDFN_Rect& src_rect, MDFN_Surface* dest_surface, const MDFN_Rect& dest_rect, bool source_alpha, int scanlines, const MDFN_Rect* original_src_rect, int rotated, int InterlaceField)
386 {
387 if(!CheckSourceRect(src_surface, &src_rect))
388 return;
389
390 if(!CheckDestRect(dest_surface, &dest_rect))
391 return;
392
393 const bool NeedClipping = CheckDRNeedsClipping(dest_surface, &dest_rect);
394
395
396 if(original_src_rect == NULL)
397 original_src_rect = &src_rect;
398
399 MDFN_Rect sr, dr, o_sr;
400
401 sr = src_rect;
402 o_sr = *original_src_rect;
403 dr = dest_rect;
404
405 //printf("%d:%d, %d:%d, %d:%d\n", sr.x, sr.w, sr.y, sr.h, src_surface->w, src_surface->h);
406
407 if(rotated != MDFN_ROTATE0)
408 {
409 if(scanlines)
410 BlitSScale<uint32, 31, true, true>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect, scanlines, rotated, InterlaceField);
411 else
412 BlitSScale<uint32, 31, true, true>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect, 0, rotated);
413
414 return;
415 }
416
417 if(sr.w == dr.w && sr.h == dr.h && (!scanlines || (sr.w == o_sr.w && sr.h == o_sr.h)))
418 {
419 switch(source_alpha ? (int)src_surface->format.Ashift : -1)
420 {
421 case -1: BlitStraight<uint32, 31>(src_surface, &sr, dest_surface, &dr); break;
422 case 0: BlitStraight<uint32, 0>(src_surface, &sr, dest_surface, &dr); break;
423 case 8: BlitStraight<uint32, 8>(src_surface, &sr, dest_surface, &dr); break;
424 case 16: BlitStraight<uint32, 16>(src_surface, &sr, dest_surface, &dr); break;
425 case 24: BlitStraight<uint32, 24>(src_surface, &sr, dest_surface, &dr); break;
426 }
427 //BlitStraight<uint32, 31>(src_surface, &sr, dest_surface, &dr);
428 //SDL_BlitSurface(src_surface, &sr, dest_surface, &dr);
429 return;
430 }
431
432 //printf("%d\n", dr.x);
433
434 double dw_to_sw_ratio = (double)dr.w / sr.w;
435 double dh_to_sh_ratio = (double)dr.h / sr.h;
436
437 if(!scanlines && !NeedClipping && floor(dw_to_sw_ratio) == dw_to_sw_ratio && floor(dh_to_sh_ratio) == dh_to_sh_ratio)
438 {
439 switch(source_alpha ? (int)src_surface->format.Ashift : -1)
440 {
441 case -1: if((dw_to_sw_ratio == dh_to_sh_ratio) && dw_to_sw_ratio <= 5)
442 nnx(dw_to_sw_ratio, src_surface, sr, dest_surface, dr);
443 else
444 BlitIScale<uint32, 31>(src_surface, sr, dest_surface, dr, dw_to_sw_ratio, dh_to_sh_ratio);
445 break;
446
447 case 0: BlitIScale<uint32, 0>(src_surface, sr, dest_surface, dr, dw_to_sw_ratio, dh_to_sh_ratio); break;
448 case 8: BlitIScale<uint32, 8>(src_surface, sr, dest_surface, dr, dw_to_sw_ratio, dh_to_sh_ratio); break;
449 case 16: BlitIScale<uint32, 16>(src_surface, sr, dest_surface, dr, dw_to_sw_ratio, dh_to_sh_ratio); break;
450 case 24: BlitIScale<uint32, 24>(src_surface, sr, dest_surface, dr, dw_to_sw_ratio, dh_to_sh_ratio); break;
451 }
452 }
453 else
454 {
455 if(scanlines)
456 {
457 BlitSScale<uint32, 31, true, false>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect, scanlines, 0, InterlaceField);
458 }
459 else switch(source_alpha ? (int)src_surface->format.Ashift : -1)
460 {
461 case -1: BlitSScale<uint32, 31, false, false>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect); break;
462 case 0: BlitSScale<uint32, 0, false, false>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect); break;
463 case 8: BlitSScale<uint32, 8, false, false>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect); break;
464 case 16: BlitSScale<uint32, 16, false, false>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect); break;
465 case 24: BlitSScale<uint32, 24, false, false>(src_surface, &src_rect, dest_surface, &dest_rect, original_src_rect); break;
466 }
467 }
468 }
469