subpixelsurface.py 3.34 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# font: http://www.pygame.org/project-Sub-pixel+surface-413-.html

import pygame
from pygame.locals import *
from math import floor

# Try to import Numpy, or Numeric
try:    
    import numpy as Numeric
    BYTE = "u1"
    DWORD = "u4"
    
except ImportError:    
    try:
        import Numeric
    except ImportError as e:
        print("Requires NumPy or Numeric!")
        raise e
    BYTE = Numeric.UnsignedInt8
    DWORD = Numeric.Int32
    

class SubPixelSurface(object):
    
    
    def __init__(self, surface, x_level=3, y_level=None):
        
        """Creates a sub pixel surface object.
        
        surface -- A PyGame surface
        x_level -- Number of sub-pixel levels in x
        y_level -- Number of sub-pixel levels in y (same as x if omited)        
        
        """
                
        self.x_level = x_level
        self.y_level = y_level or x_level
        
        w, h = surface.get_size()
        ow, oh = w, h        
        w += 2
        h += 2        
                
        surf_array_rgb = Numeric.zeros((w, h, 3), BYTE)
        surf_array_rgb[1:ow+1:, 1:oh+1:, ::] = pygame.surfarray.array3d(surface)
        surf_array_a = Numeric.zeros((w, h), BYTE)
        surf_array_a[1:ow+1:, 1:oh+1:] = pygame.surfarray.array_alpha(surface)
                
        surf_array_rgb[0,::] = surf_array_rgb[1,::]                
        surf_array_rgb[::,0] = surf_array_rgb[::,1]        
        surf_array_rgb[w-1,::] = surf_array_rgb[w-2,::]                
        surf_array_rgb[::,h-1] = surf_array_rgb[::,h-2]
        
        s = Numeric.zeros(surf_array_rgb.shape[:2]+(4,), DWORD)
        s[::-1, ::, :3] = surf_array_rgb
        s[::-1, ::, 3] = surf_array_a
        
        x_steps = [float(n) / self.x_level for n in range(self.x_level)]
        y_steps = [float(n) / self.y_level for n in range(self.y_level)]
        
        self.surfaces = []
        for frac_y in y_steps:
            row = []
            self.surfaces.append(row)
            for frac_x in x_steps:
                row.append( SubPixelSurface._generate(s, frac_x, frac_y) )
                
        
    @staticmethod
    def _generate(s, frac_x, frac_y):        
        
        frac_x, frac_y = frac_y, frac_x
        frac_x = 1. - frac_x        
        
        sa = int( (1.-frac_x) * (1.-frac_y) * 255. ) 
        sb = int( (1.-frac_x) * frac_y * 255. )
        sc = int( frac_x * (1.-frac_y) * 255. )
        sd = int( (frac_x * frac_y) * 255. )
        
        a = s[ :-1:, :-1:] * sa
        b = s[ 1::,  :-1:] * sb
        c = s[ :-1:, 1:: ] * sc
        d = s[ 1::,  1:: ] * sd
        
        a += b
        a += c
        a += d
        a >>= 8
        
        rgba_data = a.astype(BYTE).tostring()
        pygame_surface = pygame.image.fromstring(rgba_data, a.shape[:2][::-1], "RGBA")
        pygame_surface = pygame.transform.rotate(pygame_surface, 270)
        
        return pygame_surface
        
        
    def at(self, x, y):
        
        """Gets a sub-pixel surface for a given coordinate.
        
        x -- X coordinate
        y -- Y coordinate
        
        """
        
        surf_x = int( (x - floor(x)) * self.x_level )
        surf_y = int( (y - floor(y)) * self.y_level )
        
        return self.surfaces[surf_y][surf_x]