Skip to content

Commit

Permalink
implement transform.scale2x, moveit and liquid examples work
Browse files Browse the repository at this point in the history
  • Loading branch information
Rizziepit committed Mar 14, 2014
1 parent 32fb910 commit 7d0b48a
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 46 deletions.
4 changes: 4 additions & 0 deletions pygame/_sdl.py
Expand Up @@ -582,6 +582,7 @@
int pygame_Blit (SDL_Surface * src, SDL_Rect * srcrect,
SDL_Surface * dst, SDL_Rect * dstrect, int the_args);
int surface_fill_blend (SDL_Surface *surface, SDL_Rect *rect, Uint32 color, int blendargs);
void scale2x(SDL_Surface *src, SDL_Surface *dst);
""")

Expand Down Expand Up @@ -866,10 +867,13 @@
%(alphablit)s
%(surface_fill)s
%(scale2x)s
""" % {
'surface_h': getResource('lib/surface.h').read(),
'alphablit': getResource('lib/alphablit.c').read(),
'surface_fill': getResource('lib/surface_fill.c').read(),
'scale2x': getResource('lib/scale2x.c').read(),
}
)

Expand Down
156 changes: 156 additions & 0 deletions pygame/lib/scale2x.c
@@ -0,0 +1,156 @@
/*
pygame - Python Game Library
Copyright (C) 2000-2001 Pete Shinners
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Pete Shinners
pete@shinners.org
*/

/*
This implements the AdvanceMAME Scale2x feature found on this page,
http://advancemame.sourceforge.net/scale2x.html
It is an incredibly simple and powerful image doubling routine that does
an astonishing job of doubling game graphic data while interpolating out
the jaggies. Congrats to the AdvanceMAME team, I'm very impressed and
surprised with this code!
*/



#define MAX(a,b) (((a) > (b)) ? (a) : (b))
// already defined
//#define MIN(a,b) (((a) < (b)) ? (a) : (b))


#define READINT24(x) ((x)[0]<<16 | (x)[1]<<8 | (x)[2])
#define WRITEINT24(x, i) {(x)[0]=i>>16; (x)[1]=(i>>8)&0xff; x[2]=i&0xff; }

/*
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.
*/

void scale2x(SDL_Surface *src, SDL_Surface *dst)
{
int looph, loopw;

Uint8* srcpix = (Uint8*)src->pixels;
Uint8* dstpix = (Uint8*)dst->pixels;

const int srcpitch = src->pitch;
const int dstpitch = dst->pitch;
const int width = src->w;
const int height = src->h;

switch(src->format->BytesPerPixel)
{
case 1: {
Uint8 E0, E1, E2, E3, B, D, E, F, H;
for(looph = 0; looph < height; ++looph)
{
for(loopw = 0; loopw < width; ++ loopw)
{
B = *(Uint8*)(srcpix + (MAX(0,looph-1)*srcpitch) + (1*loopw));
D = *(Uint8*)(srcpix + (looph*srcpitch) + (1*MAX(0,loopw-1)));
E = *(Uint8*)(srcpix + (looph*srcpitch) + (1*loopw));
F = *(Uint8*)(srcpix + (looph*srcpitch) + (1*MIN(width-1,loopw+1)));
H = *(Uint8*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (1*loopw));

E0 = D == B && B != F && D != H ? D : E;
E1 = B == F && B != D && F != H ? F : E;
E2 = D == H && D != B && H != F ? D : E;
E3 = H == F && D != H && B != F ? F : E;

*(Uint8*)(dstpix + looph*2*dstpitch + loopw*2*1) = E0;
*(Uint8*)(dstpix + looph*2*dstpitch + (loopw*2+1)*1) = E1;
*(Uint8*)(dstpix + (looph*2+1)*dstpitch + loopw*2*1) = E2;
*(Uint8*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*1) = E3;
}
}break;}
case 2: {
Uint16 E0, E1, E2, E3, B, D, E, F, H;
for(looph = 0; looph < height; ++looph)
{
for(loopw = 0; loopw < width; ++ loopw)
{
B = *(Uint16*)(srcpix + (MAX(0,looph-1)*srcpitch) + (2*loopw));
D = *(Uint16*)(srcpix + (looph*srcpitch) + (2*MAX(0,loopw-1)));
E = *(Uint16*)(srcpix + (looph*srcpitch) + (2*loopw));
F = *(Uint16*)(srcpix + (looph*srcpitch) + (2*MIN(width-1,loopw+1)));
H = *(Uint16*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (2*loopw));

E0 = D == B && B != F && D != H ? D : E;
E1 = B == F && B != D && F != H ? F : E;
E2 = D == H && D != B && H != F ? D : E;
E3 = H == F && D != H && B != F ? F : E;

*(Uint16*)(dstpix + looph*2*dstpitch + loopw*2*2) = E0;
*(Uint16*)(dstpix + looph*2*dstpitch + (loopw*2+1)*2) = E1;
*(Uint16*)(dstpix + (looph*2+1)*dstpitch + loopw*2*2) = E2;
*(Uint16*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*2) = E3;
}
}break;}
case 3: {
int E0, E1, E2, E3, B, D, E, F, H;
for(looph = 0; looph < height; ++looph)
{
for(loopw = 0; loopw < width; ++ loopw)
{
B = READINT24(srcpix + (MAX(0,looph-1)*srcpitch) + (3*loopw));
D = READINT24(srcpix + (looph*srcpitch) + (3*MAX(0,loopw-1)));
E = READINT24(srcpix + (looph*srcpitch) + (3*loopw));
F = READINT24(srcpix + (looph*srcpitch) + (3*MIN(width-1,loopw+1)));
H = READINT24(srcpix + (MIN(height-1,looph+1)*srcpitch) + (3*loopw));

E0 = D == B && B != F && D != H ? D : E;
E1 = B == F && B != D && F != H ? F : E;
E2 = D == H && D != B && H != F ? D : E;
E3 = H == F && D != H && B != F ? F : E;

WRITEINT24((dstpix + looph*2*dstpitch + loopw*2*3), E0);
WRITEINT24((dstpix + looph*2*dstpitch + (loopw*2+1)*3), E1);
WRITEINT24((dstpix + (looph*2+1)*dstpitch + loopw*2*3), E2);
WRITEINT24((dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*3), E3);
}
}break;}
default: { /*case 4:*/
Uint32 E0, E1, E2, E3, B, D, E, F, H;
for(looph = 0; looph < height; ++looph)
{
for(loopw = 0; loopw < width; ++ loopw)
{
B = *(Uint32*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*loopw));
D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MAX(0,loopw-1)));
E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw));
F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MIN(width-1,loopw+1)));
H = *(Uint32*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (4*loopw));

E0 = D == B && B != F && D != H ? D : E;
E1 = B == F && B != D && F != H ? F : E;
E2 = D == H && D != B && H != F ? D : E;
E3 = H == F && D != H && B != F ? F : E;

*(Uint32*)(dstpix + looph*2*dstpitch + loopw*2*4) = E0;
*(Uint32*)(dstpix + looph*2*dstpitch + (loopw*2+1)*4) = E1;
*(Uint32*)(dstpix + (looph*2+1)*dstpitch + loopw*2*4) = E2;
*(Uint32*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*4) = E3;
}
}break;}
}
}
105 changes: 59 additions & 46 deletions pygame/transform.py
Expand Up @@ -41,53 +41,52 @@ def flip(surface, xaxis, yaxis):
bpp = c_surf.format.BytesPerPixel
pitch = c_surf.pitch

sdl.SDL_LockSurface(new_surf)
with locked(surface._c_surface):
# only have to deal with rows
if not xaxis:
srcpixels = ffi.cast('uint8_t*', c_surf.pixels)
destpixels = ffi.cast('uint8_t*', new_surf.pixels)
if not yaxis:
# no changes - just copy pixels
destpixels[0:h * pitch] = srcpixels[0:h * pitch]
else:
for y in range(h):
dest_start = (h - y - 1) * pitch
src_start = y * pitch
destpixels[dest_start:dest_start + pitch] = \
srcpixels[src_start:src_start + pitch]
# have to calculate position for individual pixels
else:
if not yaxis:
def get_y(y):
return y
else:
def get_y(y):
return h - y - 1

if bpp in (1, 2, 4):
ptr_type = 'uint%s_t*' % c_surf.format.BitsPerPixel
srcpixels = ffi.cast(ptr_type, c_surf.pixels)
destpixels = ffi.cast(ptr_type, new_surf.pixels)
for y in range(h):
dest_row_start = get_y(y) * w
src_row_start = y * w
for x in range(w):
destpixels[dest_row_start + (w - x - 1)] = \
srcpixels[src_row_start + x]
else:
with locked(new_surf):
with locked(surface._c_surface):
# only have to deal with rows
if not xaxis:
srcpixels = ffi.cast('uint8_t*', c_surf.pixels)
destpixels = ffi.cast('uint8_t*', new_surf.pixels)
for y in range(h):
dest_row_start = get_y(y) * pitch
src_row_start = y * pitch
for x in range(0, pitch, 3):
dest_pix_start = dest_row_start + (pitch - x - 3)
src_pix_start = src_row_start + x
destpixels[dest_pix_start:dest_pix_start + 3] = \
srcpixels[src_pix_start:src_pix_start + 3]

sdl.SDL_UnlockSurface(new_surf)
if not yaxis:
# no changes - just copy pixels
destpixels[0:h * pitch] = srcpixels[0:h * pitch]
else:
for y in range(h):
dest_start = (h - y - 1) * pitch
src_start = y * pitch
destpixels[dest_start:dest_start + pitch] = \
srcpixels[src_start:src_start + pitch]
# have to calculate position for individual pixels
else:
if not yaxis:
def get_y(y):
return y
else:
def get_y(y):
return h - y - 1

if bpp in (1, 2, 4):
ptr_type = 'uint%s_t*' % c_surf.format.BitsPerPixel
srcpixels = ffi.cast(ptr_type, c_surf.pixels)
destpixels = ffi.cast(ptr_type, new_surf.pixels)
for y in range(h):
dest_row_start = get_y(y) * w
src_row_start = y * w
for x in range(w):
destpixels[dest_row_start + (w - x - 1)] = \
srcpixels[src_row_start + x]
else:
srcpixels = ffi.cast('uint8_t*', c_surf.pixels)
destpixels = ffi.cast('uint8_t*', new_surf.pixels)
for y in range(h):
dest_row_start = get_y(y) * pitch
src_row_start = y * pitch
for x in range(0, pitch, 3):
dest_pix_start = dest_row_start + (pitch - x - 3)
src_pix_start = src_row_start + x
destpixels[dest_pix_start:dest_pix_start + 3] = \
srcpixels[src_pix_start:src_pix_start + 3]

return Surface._from_sdl_surface(new_surf)


Expand All @@ -113,7 +112,21 @@ def scale2x(surface, dest_surface=None):
""" scale2x(Surface, DestSurface = None) -> Surface
specialized image doubler
"""
raise NotImplementedError
c_surf = surface._c_surface
if dest_surface:
new_surf = dest_surface._c_surface
if (new_surf.w != 2 * c_surf.w) or (new_surf.h != 2 * c_surf.h):
raise ValueError("Destination surface not 2x bigger")
else:
new_surf = new_surface_from_surface(c_surf, c_surf.w * 2, c_surf.h * 2)

with locked(new_surf):
with locked(c_surf):
sdl.scale2x(c_surf, new_surf)

if dest_surface:
return dest_surface
return Surface._from_sdl_surface(new_surf)


def smoothscale(surface, (width, height), dest_surface=None):
Expand Down

0 comments on commit 7d0b48a

Please sign in to comment.