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