Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/olpcgames/_cairoimage.py
diff options
context:
space:
mode:
authorManuel Kaufmann <humitos@gmail.com>2012-03-27 13:15:10 (GMT)
committer Rafael Ortiz <rafael@activitycentral.com>2012-03-28 18:05:22 (GMT)
commit335ad73456ba3ec8f56811abddcaca4650199db1 (patch)
treedb788baba57c7656c9bdb73eb9003a70dc87d59a /olpcgames/_cairoimage.py
parent6deeb3f569e6c9a1c02a32a011b7a96a58fa8443 (diff)
Save and restore state of the game
Ability to 'save' (when the user closes the Activity) and 'restore' (when the user launch it from the Journal or the Home without holding Alt) the state of the game. For this ability I had to upgrade 'olpcgames' to 1.6 because 'olpcgames.FILE_READ_REQUEST' and 'olpcgames.FILE_WRITE_REQUEST' events are added in that version and those events are needed for this. The data is saved (as JSON, with json module) in the 'event.metadata["state"]' and the timestamp state is saved in 'event.filename'. This commit solves ticket #2393: * http://bugs.sugarlabs.org/ticket/2393 Signed-off-by: Manuel Kaufmann <humitos@gmail.com> Signed-off-by: Rafael Ortiz <rafael@activitycentral.com>
Diffstat (limited to 'olpcgames/_cairoimage.py')
-rw-r--r--olpcgames/_cairoimage.py97
1 files changed, 87 insertions, 10 deletions
diff --git a/olpcgames/_cairoimage.py b/olpcgames/_cairoimage.py
index 302b916..3cfa22c 100644
--- a/olpcgames/_cairoimage.py
+++ b/olpcgames/_cairoimage.py
@@ -1,23 +1,38 @@
-"""Utility functions for cairo-specific operations"""
-import cairo, pygame, struct
+"""Utility functions for cairo-specific operations
+
+USE_BASE_ARRAY -- if False (default), uses numpy arrays,
+ currently this is the only version that works on 32-bit
+ machines.
+"""
+import pygame, struct, logging
big_endian = struct.pack( '=i', 1 ) == struct.pack( '>i', 1 )
+log = logging.getLogger( 'olpcgames._cairoimage' )
+##log.setLevel( logging.DEBUG )
+
+USE_BASE_ARRAY = False
+
def newContext( width, height ):
"""Create a new render-to-image context
width, height -- pixel dimensions to be rendered
- returns surface, context for rendering
+ Produces an ARGB format Cairo ImageSurface for
+ rendering your data into using rsvg, Cairo or Pango.
+
+ returns (ImageSurface, CairoContext) for rendering
"""
+ import cairo
csrf = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
- return csrf, cairo.Context (csrf)
+ context = cairo.Context (csrf)
+ #log.info( 'Format (expect: %s): %s', cairo.FORMAT_ARGB32, csrf.get_format())
+ return csrf, context
def mangle_color(color):
"""Mange a colour depending on endian-ness, and swap-necessity
- This implementation has only been tested on an AMD64
- machine with a get_data implementation (rather than
- a get_data_as_rgba implementation).
+ Converts a 3 or 4 int (or float) value in the range 0-255 into a
+ 4-float value in the range 0.0-1.0
"""
r,g,b = color[:3]
if len(color) > 3:
@@ -31,23 +46,58 @@ def _fixColorBase( v ):
return max((0,min((v,255.0))))/255.0
def asImage( csrf ):
- """Get the pixels in csrf as a Pygame image"""
+ """Get the pixels in csrf as a Pygame image
+
+ Note that Pygame 1.7.1 on (Gentoo Linux) AMD64 is incorrectly
+ calculating the required size ARGB images, so this code will *not* work
+ on that platform with that version of the library. Pygame-ctypes
+ does work correctly there.
+
+ Note also that Pygame 1.7.1 is showing a strange colour rotation
+ bug on 32-bit platforms, such that ARGB mode cannot be used for
+ images there. Instead we have to do an expensive bit-shift operation
+ to produce an RGBA image from the ARGB native Cairo format.
+
+ Will raise a ValueError if passed a Null image (i.e. dimension of 0)
+
+ returns Pygame.Surface (image) with convert_alpha() called for it.
+ """
# Create and return a new Pygame Image derived from the Cairo Surface
format = 'ARGB'
if hasattr(csrf,'get_data'):
# more recent API, native-format, but have to (potentially) convert the format...
+ log.debug( 'Native-mode api (get_data)' )
data = csrf.get_data()
if not big_endian:
- import numpy
- data = numpy.frombuffer( data, 'I' ).astype( '>I4' ).tostring()
+ # we use array here because it's considerably lighter-weight
+ # to import than the numpy module
+ log.debug( 'Not big-endian, byte-swapping array' )
+ if USE_BASE_ARRAY:
+ import array
+ a = array.array( 'I' )
+ a.fromstring( data )
+ a.byteswap()
+ data = a.tostring()
+ else:
+ import numpy
+ n = numpy.fromstring( data, dtype='I' )
+ n = ((n & 0xff000000) >> 24 ) | ((n & 0x00ffffff) << 8 )
+ n = n.byteswap()
+ data = n.tostring()
+ format = 'RGBA'
else:
+ log.debug( 'Big-endian, array unchanged' )
data = str(data) # there's one copy
else:
# older api, not native, but we know what it is...
+ log.debug( 'Non-native mode api, explicitly RGBA' )
data = csrf.get_data_as_rgba()
data = str(data) # there's one copy
+ format = 'RGBA'
width, height = csrf.get_width(),csrf.get_height()
+
try:
+ log.info( 'Format = %s', format )
return pygame.image.fromstring(
data,
(width,height),
@@ -56,3 +106,30 @@ def asImage( csrf ):
except ValueError, err:
err.args += (len(data), (width,height), width*height*4,format )
raise
+
+if __name__ == "__main__":
+ import unittest
+ logging.basicConfig()
+ class Tests( unittest.TestCase ):
+ def test_colours( self ):
+ """Test that colours are correctly translated
+
+ If we draw a given colour in cairo, we want the same
+ colour to show up in Pygame, let's test that...
+ """
+ for sourceColour in [
+ (255,0,0, 255),
+ (0,255,0, 255),
+ (0,0,255, 255),
+ (255,255,0, 255),
+ (0,255,255,255),
+ (255,0,255,255),
+ ]:
+ csrf,cctx = newContext( 1,1 )
+ background = mangle_color( sourceColour )
+ cctx.set_source_rgba(*background)
+ cctx.paint()
+ img = asImage( csrf )
+ colour = img.get_at( (0,0))
+ assert colour == sourceColour, (sourceColour,mangle_color(sourceColour),colour)
+ unittest.main()