summaryrefslogtreecommitdiff
path: root/src/libs/graphics/sdl/2xscalers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/graphics/sdl/2xscalers.c')
-rw-r--r--src/libs/graphics/sdl/2xscalers.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/libs/graphics/sdl/2xscalers.c b/src/libs/graphics/sdl/2xscalers.c
new file mode 100644
index 0000000..a612d2c
--- /dev/null
+++ b/src/libs/graphics/sdl/2xscalers.c
@@ -0,0 +1,260 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "libs/graphics/sdl/sdl_common.h"
+#include "types.h"
+#include "scalers.h"
+#include "scaleint.h"
+#include "2xscalers.h"
+
+
+// Scaler function lookup table
+//
+const Scale_FuncDef_t
+Scale_C_Functions[] =
+{
+ {TFB_GFXFLAGS_SCALE_BILINEAR, Scale_BilinearFilter},
+ {TFB_GFXFLAGS_SCALE_BIADAPT, Scale_BiAdaptFilter},
+ {TFB_GFXFLAGS_SCALE_BIADAPTADV, Scale_BiAdaptAdvFilter},
+ {TFB_GFXFLAGS_SCALE_TRISCAN, Scale_TriScanFilter},
+ {TFB_GFXFLAGS_SCALE_HQXX, Scale_HqFilter},
+ // Default
+ {0, Scale_Nearest}
+};
+
+// See
+// nearest2x.c -- Nearest Neighboor scaling
+// bilinear2x.c -- Bilinear scaling
+// biadv2x.c -- Advanced Biadapt scaling
+// triscan2x.c -- Triscan scaling
+
+// Biadapt scaling to 2x
+void
+SCALE_(BiAdaptFilter) (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
+{
+ int x, y;
+ const int w = src->w, h = src->h;
+ int xend, yend;
+ int dsrc, ddst;
+ SDL_Rect *region = r;
+ SDL_Rect limits;
+ SDL_PixelFormat *fmt = dst->format;
+ const int sp = src->pitch, dp = dst->pitch;
+ const int bpp = fmt->BytesPerPixel;
+ const int slen = sp / bpp, dlen = dp / bpp;
+ Uint32 *src_p = (Uint32 *)src->pixels;
+ Uint32 *dst_p = (Uint32 *)dst->pixels;
+ Uint32 pixval_tl, pixval_tr, pixval_bl, pixval_br;
+
+ // these macros are for clarity; they make the current pixel (0,0)
+ // and allow to access pixels in all directions
+ #define SRC(x, y) (src_p + (x) + ((y) * slen))
+
+ SCALE_(PlatInit) ();
+
+ // expand updated region if necessary
+ // pixels neighbooring the updated region may
+ // change as a result of updates
+ limits.x = 0;
+ limits.y = 0;
+ limits.w = src->w;
+ limits.h = src->h;
+ Scale_ExpandRect (region, 2, &limits);
+
+ xend = region->x + region->w;
+ yend = region->y + region->h;
+ dsrc = slen - region->w;
+ ddst = (dlen - region->w) * 2;
+
+ // move ptrs to the first updated pixel
+ src_p += slen * region->y + region->x;
+ dst_p += (dlen * region->y + region->x) * 2;
+
+ for (y = region->y; y < yend; ++y, dst_p += ddst, src_p += dsrc)
+ {
+ for (x = region->x; x < xend; ++x, ++src_p, ++dst_p)
+ {
+ pixval_tl = SCALE_GETPIX (SRC (0, 0));
+
+ SCALE_SETPIX (dst_p, pixval_tl);
+
+ if (y + 1 < h)
+ {
+ // check pixel below the current one
+ pixval_bl = SCALE_GETPIX (SRC (0, 1));
+
+ if (pixval_tl == pixval_bl)
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ else
+ SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
+ pixval_tl, pixval_bl)
+ );
+ }
+ else
+ {
+ // last pixel in column - propagate
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ pixval_bl = pixval_tl;
+ }
+ ++dst_p;
+
+ if (x + 1 >= w)
+ {
+ // last pixel in row - propagate
+ SCALE_SETPIX (dst_p, pixval_tl);
+
+ if (pixval_tl == pixval_bl)
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ else
+ SCALE_SETPIX (dst_p + dlen, Scale_Blend_11 (
+ pixval_tl, pixval_bl)
+ );
+ continue;
+ }
+
+ // check pixel to the right from the current one
+ pixval_tr = SCALE_GETPIX (SRC (1, 0));
+
+ if (pixval_tl == pixval_tr)
+ SCALE_SETPIX (dst_p, pixval_tr);
+ else
+ SCALE_SETPIX (dst_p, Scale_Blend_11 (
+ pixval_tl, pixval_tr)
+ );
+
+ if (y + 1 >= h)
+ {
+ // last pixel in column - propagate
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ continue;
+ }
+
+ // check pixel to the bottom-right
+ pixval_br = SCALE_GETPIX (SRC (1, 1));
+
+ if (pixval_tl == pixval_br && pixval_tr == pixval_bl)
+ {
+ int cl, cr;
+ Uint32 clr;
+
+ if (pixval_tl == pixval_tr)
+ {
+ // all 4 are equal - propagate
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ continue;
+ }
+
+ // both pairs are equal, have to resolve the pixel
+ // race; we try detecting which color is
+ // the background by looking for a line or an edge
+ // examine 8 pixels surrounding the current quad
+
+ cl = cr = 1;
+
+ if (x > 0)
+ {
+ clr = SCALE_GETPIX (SRC (-1, 0));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+
+ clr = SCALE_GETPIX (SRC (-1, 1));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+ }
+
+ if (y > 0)
+ {
+ clr = SCALE_GETPIX (SRC (0, -1));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+
+ clr = SCALE_GETPIX (SRC (1, -1));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+ }
+
+ if (x + 2 < w)
+ {
+ clr = SCALE_GETPIX (SRC (2, 0));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+
+ clr = SCALE_GETPIX (SRC (2, 1));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+ }
+
+ if (y + 2 < h)
+ {
+ clr = SCALE_GETPIX (SRC (0, 2));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+
+ clr = SCALE_GETPIX (SRC (1, 2));
+ if (clr == pixval_tl)
+ cl++;
+ else if (clr == pixval_tr)
+ cr++;
+ }
+
+ // least count wins
+ if (cl > cr)
+ SCALE_SETPIX (dst_p + dlen, pixval_tr);
+ else if (cr > cl)
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ else
+ SCALE_SETPIX (dst_p + dlen,
+ Scale_Blend_11 (pixval_tl, pixval_tr));
+ }
+ else if (pixval_tl == pixval_br)
+ {
+ // main diagonal is same color
+ // use its value
+ SCALE_SETPIX (dst_p + dlen, pixval_tl);
+ }
+ else if (pixval_tr == pixval_bl)
+ {
+ // 2nd diagonal is same color
+ // use its value
+ SCALE_SETPIX (dst_p + dlen, pixval_tr);
+ }
+ else
+ {
+ // blend all 4
+ SCALE_SETPIX (dst_p + dlen, Scale_Blend_1111 (
+ pixval_tl, pixval_bl, pixval_tr, pixval_br
+ ));
+ }
+ }
+ }
+
+ SCALE_(PlatDone) ();
+}
+