I went ahead and did it, though this implementation is for 32-bit color and FPC only. It will probably port to Delphi or others with very little effort. My cpu stays at 60% with an 800x600x32x60fps SDL window. That could probably be sped up by moving the final render(the one onto the screen) to OpenGL.
![](http://img383.imageshack.us/img383/9592/scale2xrz3.th.png)
(a screen shot of Cave Story run through the scaler.)
Code:
(*
32-bit only scale2x for SDL; by James Hofmann 2007
based on Pete Shinners' SDL scale2x.
Doubles the size of a surface with a smoothing algorithm.
This code is public domain.
*)
{$inline on}
{$mode objfpc}
unit scale2x32;
interface
uses sdl,sdl_video;
procedure scale2x(const src : PSDL_Surface; var dst : PSDL_Surface);
implementation
function max(const a,b : longint) : longint; inline;
begin
{ note: if we were to use unsigned numbers the border checks would cause a crash
because there would be a negative overflow }
if (a>b) then result:=a else result:=b;
end;
function min(const a,b : longint) : longint; inline;
begin
if (a<b) then result:=a else result:=b;
end;
(*
this requires a destination surface already setup to be twice as
large as the source. oh, and formats must match too. this will just
blindly assume you didn't flounder.
*)
procedure scale2x(const src : PSDL_Surface; var dst : PSDL_Surface);
var
srclinewidth : longint;
dstlinewidth : longint;
width : longint;
height : longint;
srcpix, dstpix : ^longint;
E0, E1, E2, E3, B, D, E, F, H : longint;
looph, loopw : longint;
begin
srclinewidth := (src^.pitch) div sizeof(longword);
dstlinewidth := (dst^.pitch) div sizeof(longword);
width := src^.w;
height := src^.h;
srcpix := src^.pixels;
dstpix := dst^.pixels;
for looph := 0 to height-1 do
begin
for loopw := 0 to width-1 do
begin
{ from this grid we get the values BDEFH:
ABC
DEF
GHI
and map them into a E0,E1,E2,E3:
E0 E1
E2 E3
we must also account for the borders(using the pixels nearest to border)
}
{ increment each pointer to the requested pixel }
B := (srcpix + srclinewidth * MAX(0,looph-1) + loopw)^;
D := (srcpix + srclinewidth * looph + MAX(0,loopw-1))^;
E := (srcpix + srclinewidth * looph + loopw)^;
F := (srcpix + srclinewidth * looph + MIN(width-1,loopw+1))^;
H := (srcpix + srclinewidth * MIN(height-1,looph+1) + loopw)^;
{ determine smoothing result }
if ((D = B) and (B <> F) and (D <> H)) then e0:=D else e0:=E;
if ((B = F) and (B <> D) and (F <> H)) then e1:=F else e1:=E;
if ((D = H) and (D <> B) and (H <> F)) then e2:=D else e2:=E;
if ((H = F) and (D <> H) and (B <> F)) then e3:=F else e3:=E;
{ blit the doubled pixel }
(dstpix+(looph*2*dstlinewidth + loopw*2))^:=E0;
(dstpix+(looph*2*dstlinewidth + (loopw*2+1)))^:=E1;
(dstpix+((looph*2+1)*dstlinewidth + loopw*2))^:=E2;
(dstpix+((looph*2+1)*dstlinewidth + (loopw*2+1)))^:=E3;
end;
end;
end;
end.
edit: optimized to remove unnecessary pointer and temp-value assignments.
Bookmarks