After releasing PSP Stackless Python 2.5.1 last week, I started working on a project site to host the files, sources, documentation and issues for my Stackless Python port for the PSP.
You can reach the project here: http://pspstacklesspython.googlecode.com/
There you will find the Stackless Python 2.5.1 for PSP, now including a readme to clarify the installation and usage process, a Wiki that contains information on module usage, references to the modules ported by fraca7, build the interpreter from source, etc... I tried to condensate all information I posted on this blog to have it in one central place.
In the project page, one can create issues to report problems, feature requests and even patches to correct problems.
I created a zipped source for the last release and I`m also in process of uploading the code to the SVN repository.
I hope this makes the Stackless Python for PSP widespread and within reach of everyone, also dont forget to keep an eye on Stackless Examples Project, where you can find nice use cases for it.
Carlos
After working some time on it, I have updated the Stackless Python for PSP to version 2.5.1, the latest version released and made the application user mode tested on 3.71 firmware.
In this release, I have fixes the problem exiting the application (where it locked the PSP) and tested many other functionality.
Here follows changes between last version:
- The SSL has been removed for now because it was not working on latest release.
- Fixed time and datetime modules to display correct dates and times based on PSP timezones and DST.
- Fixed problems on sys and os modules
- Ported to user mode and 3.xx kernel.
I hope many people could test this release and post feedbacks about it.
The package can be downloaded from here: http://stacklesspsp.googlepages.com/StacklessPSP2.5.1_1.zip
The installation is the same, put the "python" directory on your MS root and place the EBOOT.PBP in your PSP/GAME3xx or GAME dir if you set it to run 3.xx apps.
Check my older posts about module usage and tips. Also check this video posted by Domino Man showing a simple demo provided in this zip.
Carlos
Its great to see that the effort from the best developers around gets alive.
Congratulations to Guido and all the team committed to make this all happen and providing us this great language.
You can grab it here: http://python.org/download/releases/3.0/
For a long time I wanted to create a module to allow asynchronous file IO for Stackless Python.
The problem is that the currently available file object, does blocking calls to the read() and write() methods making all the interpreter block and not permitting the other tasklets do its job.
The solution was to create a module where the tasklet calls the method and only he gets blocked in the channel allowing other tasklets run freely... when the data is read/wrote a manager fires back to the channel and the requester tasklet continues.
I have already created a module using a threadpool where the requests are fired, the workers read or write the data and returns back to the calling tasklet but this consumes memory for the multiple OS threads running as workers and you have to configure the worker quantity based on your usage.
Fiddling around I found that on windows select() doesn't support file descriptors so the other option was OverlappedIO also known as IOCP.
This made me learn a thousand things I thought would never know... Ctypes, Windows internal APIs (kernel32 stuff), and even python internals to see how its fileobject works.
After this all here it is, the module that mimics the internal python file() object. Please test it and report any successes or failures. I also made a script to test its usage.
Hope it's useful.
Carlos
The code is below, if its too difficult to read, it is pasted here: http://dpaste.com/hold/17151/ and will be posted on Stackless Examples SVN
#
# Stackless Asynchronous file module:
#
# Author: Carlos E. de Paula <carlosedp@gmail.com>
#
# This code was written to serve as an example of Stackless Python usage.
# Feel free to email me with any questions, comments, or suggestions for
# improvement.
#
# This is an asynchronous file class in order to have a file module replacement
# that uses channels and a windows async API to allow its methods to
# block just the calling tasklet not the entire interpreter.
#
#
import os
import time
import stackless
from ctypes import *
from ctypes.wintypes import HANDLE, ULONG, DWORD, BOOL, LPCSTR, LPCWSTR, WinError
# Verify module compatibility
if os.name != 'nt':
raise ImportError('This module has been implemented for windows systems.')
# Windows structures
class _US(Structure):
_fields_ = [
("Offset", DWORD),
("OffsetHigh", DWORD),
]
class _U(Union):
_fields_ = [
("s", _US),
("Pointer", c_void_p),
]
_anonymous_ = ("s",)
class OVERLAPPED(Structure):
_fields_ = [
("Internal", POINTER(ULONG)),
("InternalHigh", POINTER(ULONG)),
("u", _U),
("hEvent", HANDLE),
# Custom fields.
("taskletID", ULONG),
]
_anonymous_ = ("u",)
# Windows kernel32 API
CreateIoCompletionPort = windll.kernel32.CreateIoCompletionPort
CreateIoCompletionPort.argtypes = (HANDLE, HANDLE, POINTER(c_ulong), DWORD)
CreateIoCompletionPort.restype = HANDLE
GetQueuedCompletionStatus = windll.kernel32.GetQueuedCompletionStatus
GetQueuedCompletionStatus.argtypes = (HANDLE, POINTER(DWORD), POINTER(c_ulong),
POINTER(POINTER(OVERLAPPED)), DWORD)
GetQueuedCompletionStatus.restype = BOOL
ReadFile = windll.kernel32.ReadFile
ReadFile.argtypes = (HANDLE, c_void_p, DWORD, POINTER(DWORD), POINTER(OVERLAPPED))
ReadFile.restype = BOOL
WriteFile = windll.kernel32.WriteFile
WriteFile.argtypes = (HANDLE, c_void_p, DWORD, POINTER(DWORD), POINTER(OVERLAPPED))
WriteFile.restype = BOOL
CreateFileA = windll.kernel32.CreateFileA
CreateFileA.argtypes = (LPCSTR, DWORD, DWORD, c_void_p, DWORD, DWORD, HANDLE)
CreateFileA.restype = HANDLE
CreateFileW = windll.kernel32.CreateFileW
CreateFileW.argtypes = (LPCWSTR, DWORD, DWORD, c_void_p, DWORD, DWORD, HANDLE)
CreateFileW.restype = HANDLE
CloseHandle = windll.kernel32.CloseHandle
CloseHandle.argtypes = (HANDLE,)
CloseHandle.restype = BOOL
GetLastError = windll.kernel32.GetLastError
# Python API
pythonapi.PyErr_SetFromErrno.argtypes = (py_object,)
pythonapi.PyErr_SetFromErrno.restype = py_object
# Windows definitions
INVALID_HANDLE_VALUE = 0xFFFFFFFF
NULL = c_ulong()
WAIT_TIMEOUT = 0x102
ERROR_IO_PENDING = 997
FILE_FLAG_RANDOM_ACCESS = 0x10000000
FILE_FLAG_OVERLAPPED = 0x40000000
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
FILE_APPEND_DATA = 0x00000004
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
OPEN_EXISTING = 3
OPEN_ALWAYS = 4
CREATE_ALWAYS = 2
# ----------------------------------------------------------------------------
class resultsManager(object):
"""
Manages the results sent by the CreateIoCompletionPort call.
The resultsManager dequeues the IO requests and keeps a list of pending handles.
The taskletID is stored in OVERLAPPED structure so it can be recalled and the
signalling data sent via its channel unblocking the original tasklet.
The handle is then removed from the dict.
"""
def __init__(self, numThreads=NULL):
self.running = True
self.handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
NULL, numThreads)
if self.handle == 0:
raise WinError()
self.numThreads = numThreads
stackless.tasklet(self.poll)()
self.overlappedByID = {}
def __del__(self):
if self.handle is None:
return
self.overlappedByID.clear()
CloseHandle(self.handle)
def poll(self, timeout=1):
while self.running and self.overlappedByID:
numBytes = DWORD()
completionKey = c_ulong()
ovp = POINTER(OVERLAPPED)()
ret = GetQueuedCompletionStatus(self.handle, byref(numBytes),
byref(completionKey), byref(ovp),
timeout)
if not ovp and ret == 0:
if GetLastError() == WAIT_TIMEOUT:
stackless.schedule()
continue
if ovp.contents.taskletID in self.overlappedByID:
#print ovp.contents.taskletID, " tasklet ID IN pool"
c = self.overlappedByID[ovp.contents.taskletID]
else:
#print ovp.contents.taskletID, " tasklet ID NOT in pool"
continue
#print "sending data back to channel in ID", ovp.contents.taskletID
c.send(numBytes)
#print "sent data to channel in ID", ovp.contents.taskletID, numBytes
self.UnregisterChannelObject(ovp.contents.taskletID)
self.running = False
def RegisterChannelObject(self, ob, c):
self.overlappedByID[ob] = c
def UnregisterChannelObject(self, ob):
if self.overlappedByID.has_key(ob):
del self.overlappedByID[ob]
mng = resultsManager()
class stacklessfile(object):
"""
stacklessfile(name[, mode[, buffering]]) -> stackless file object
This class creates a new file module permitting nonblocking IO calls
for tasklets using windows IOCP functionality.
When a read or write operation is called, only the calling tasklet is
blocked. In standard file module, the whole interpreter gets blocked
until the operation is concluded.
Open a file. The mode can be 'r', 'w' or 'a' for reading (default),
writing or appending. The file will be created if it doesn't exist
when opened for writing or appending; it will be truncated when
opened for writing. Add a 'b' to the mode for binary files.
Add a '+' to the mode to allow simultaneous reading and writing.
If the buffering argument is given, 0 means unbuffered, 1 means line
buffered, and larger numbers specify the buffer size.
Add a 'U' to mode to open the file for input with universal newline
support. Any line ending in the input file will be seen as a \'\\n\'
in Python. Also, a file so opened gains the attribute 'newlines';
the value for this attribute is one of None (no newline read yet),
\'\\r\', \'\\n\', \'\\r\\n\' or a tuple containing all the newline types seen.
"""
closed = True
def __init__(self, name, mode='r', buffering=-1):
"""
Initializes the file object and creates an internal file object.
"""
if not self.closed:
self.close()
self.name = name
self.mode = mode
self.offset = 0
self.iocpLinked = False
self._check_manager()
self.open_handle()
self.closed = False
def __repr__(self):
return "<%s file '%s', mode '%s' at 0x%08X>" % ([ "open", "closed" ][self.closed], self.name, self.mode, id(self))
def __del__(self):
self.close()
def _check_manager(self):
if not mng.running:
stackless.tasklet(mng.poll)()
mng.running = True
#print "ERROR - Manager not running"
def _check_still_open(self):
if self.closed:
raise ValueError("I/O operation on closed file")
def _ensure_iocp_association(self):
if not self.iocpLinked:
CreateIoCompletionPort(self.handle, mng.handle, NULL, mng.numThreads)
self.iocpLinked = True
def close(self):
"""
close() -> None or (perhaps) an integer. Close the file.
Sets data attribute .closed to True. A closed file canno
further I/O operations. close() may be called more than
error. Some kinds of file objects (for example, opened b
may return an exit status upon closing.
"""
if not self.closed:
CloseHandle(self.handle)
del self.handle
self.closed = True
def open_handle(self):
self.binary = 'b' in self.mode
access = GENERIC_READ
if 'w' in self.mode or ('r' in self.mode and '+' in self.mode):
access |= GENERIC_WRITE
if 'a' in self.mode:
access |= FILE_APPEND_DATA
share = FILE_SHARE_READ | FILE_SHARE_WRITE
if 'w' in self.mode:
disposition = CREATE_ALWAYS
elif 'r' in self.mode and '+' in self.mode:
disposition = OPEN_ALWAYS
else:
disposition = OPEN_EXISTING
flags = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED
if isinstance(self.name, unicode):
func = CreateFileW
else:
func = CreateFileA
self.handle = func(self.name, access,
share, c_void_p(), disposition,
flags, NULL )
if self.handle == INVALID_HANDLE_VALUE:
raise WinError()
self.iocpLinked = False
def read(self, size=None):
"""
read([size]) -> read at most size bytes, returned as a string.
"""
self._check_still_open()
maxBytesToRead = int(os.path.getsize(self.name)) - self.offset
if (size is None) or (maxBytesToRead < size):
size = maxBytesToRead
bytesRead = DWORD()
self.o = OVERLAPPED()
self.o.Offset = self.offset
self.o.taskletID = id(self)
self.buffer = create_string_buffer(size)
self.channel = stackless.channel()
self._ensure_iocp_association()
self._check_manager()
#print self.o.taskletID, "ID on read", self.name
#print "firing ReadFile", self.name
r = ReadFile(self.handle, self.buffer,
size, byref(bytesRead), byref(self.o));
#print "fired ReadFile", self.name
if r == 0:
if GetLastError() != ERROR_IO_PENDING:
pythonapi.PyErr_SetExcFromWindowsErrWithFilename(py_object(IOError),
0, c_char_p(self.name))
mng.RegisterChannelObject(self.o.taskletID, self.channel)
#print "blocked on channel",self.channel, self.name, self.o.taskletID
self.channel.receive()
#print "returned from channel",self.channel, self.name, self.o.taskletID
self.offset += size
return self.buffer[:size]
def write(self, data):
"""
write(str) -> None. Write string str to file.
"""
self._check_still_open()
bytesToWrite = c_int()
writeBufferPtr = c_char_p()
bytesWritten = DWORD()
self.o = OVERLAPPED()
self.o.Offset = self.offset
self.o.taskletID = id(self)
self.channel = stackless.channel()
self._ensure_iocp_association()
self._check_manager()
#print self.o.taskletID, "ID on write", self.name
fmt = self.binary and "s#" or "t#"
ret = pythonapi.PyArg_ParseTuple(py_object((data,)), c_char_p(fmt),
byref(writeBufferPtr), byref(bytesToWrite))
if ret == 0:
raise WinError()
#print "firing WriteFile", self.name
r = WriteFile(self.handle, writeBufferPtr,
bytesToWrite.value, byref(bytesWritten), byref(self.o))
#print "fired WriteFile", self.name
if r == 0:
if GetLastError() != ERROR_IO_PENDING:
pythonapi.PyErr_SetExcFromWindowsErrWithFilename(py_object(IOError),
0, c_char_p(self.name))
mng.RegisterChannelObject(self.o.taskletID, self.channel)
#print "blocked on channel",self.channel, self.name, self.o.taskletID
written = self.channel.receive()
#print "returned from channel",self.channel, self.name, self.o.taskletID
else:
written = bytesWritten
#print "Checking contents...", bytesToWrite.value, written.value, self.name
if bytesToWrite.value != written.value:
# Check if the quantity of bytes sent has been written to the file
#print self.o.taskletID, "size mismatch"
raise WinError()
def tell(self):
"""
tell() -> current file position, an integer (may be a long integer).
"""
return self.offset
def seek(self, offset, whence=os.SEEK_SET):
"""
seek(offset[, whence]) -> None. Move to new file position.
Argument offset is a byte count. Optional argument whence defaults to
0 (offset from start of file, offset should be >= 0); other values are 1
(move relative to current position, positive or negative), and 2 (move
relative to end of file, usually negative, although many platforms allow
seeking beyond the end of a file). If the file is opened in text mode,
only offsets returned by tell() are legal. Use of other offsets causes
undefined behavior.
Note that not all file objects are seekable.
"""
self._check_still_open()
if whence == os.SEEK_SET:
self.offset = offset
elif whence == os.SEEK_CUR:
self.offset += offset
elif whence == os.SEEK_END:
raise RuntimeError("SEEK_END unimplemented")
def flush(self):
pass
def isatty(self):
"""
isatty() -> true or false. True if the file is connected to a tty device.
"""
self._check_still_open()
return False
def isatty(self):
self._check_still_open()
return False
if __name__ == '__main__':
import time
import glob
import os
stdfile = file
# On your stackless apps, use these 2 lines below
from stacklessfile import stacklessfile as file
open = file
# Function to copy a file
def copyfile(who, infile, out):
st = time.time()
f1 = file(infile, 'rb')
f2 = file(out, 'wb')
print "%s started reading %s ..." % (who, infile)
a = f1.read()
print "%s started writing %s -> %s ..." % (who, infile, out)
f2.write(a)
f1.close()
f2.close()
print "Finished tasklet %s (%s) in %s" % (who, infile, time.time()-st)
# Creating two dummy files
newfile = stdfile('test-small.txt','w')
for x in xrange(10000):
newfile.write(str(x))
newfile.close()
newfile2 = stdfile('test-big.txt','w')
for x in xrange(500000):
newfile2.write(str(x))
newfile2.close()
# Launching tasklets to perform the file copy
for i in xrange(1,11):
stackless.tasklet(copyfile)(i, 'test-big.txt','big%s.txt' % i)
for i in xrange(1,21):
stackless.tasklet(copyfile)(i, 'test-small.txt','sm%s.txt' % i)
st = time.time()
stackless.run()
print "Total time is %s seconds." % (time.time() - st)
# Cleanup all test files used
for f in glob.glob('test*.txt'):
os.unlink(f)
for f in glob.glob('sm*.txt'):
os.unlink(f)
for f in glob.glob('big*.txt'):
os.unlink(f)
This morning I was delighted to see a post by Muharem Hrnjadovic post about Stackless Python. Its great to see that its usage is getting widespread and its benefits demonstrated and shown to everyone.
I'm telling this because some time ago I started to play with Erlang and liked it a lot. Because of work issues I didn't have enough time to keep my studies (I plan to buy Joe Armstrong's book) but I found it a great language and with its focus on parallel processing made me think about a comparison with Stackless.
For my surprise, it happened today on Muharen's post. He did a great job creating both apps and comparing them even with graphics demonstrating the results. It showed that Stackless is great for the job and should be considered for a lot more projects than it is now.
For more information on Stackless visit www.stackless.com, the Stackless mailing list or the Stackless Examples project hosted on http://code.google.com/p/stacklessexamples/ where we have an increasing number of samples and day to day use cases.
As the time goes by, a lot of progress has been made in my Stackless port for the Sony PSP.
Here I will list everything that changed since the last published archive:
- Time function returns correct date based on PSP Timezone
- OGG Vorbis support
- I have added a basic OGG Vorbis support for the port. The API is based on oggplayer from PSPMediaCenter. The problem is that i loads the entire file into memory and playbacks it from there. On MP3 this doesnt happens.. more below.
- The API for the OGG is very simple, a sample application follows at the end of the post.
- MP3 Support
- Its here! With the great help from Ghoti (thanks Rein) the MP3 streaming playback is now available transparently. What streaming means? Your application wont load the entire file into memory for playback. The application creates a buffer and loads small chunks from disk as needed. This leaves a lot of memory to the interpreter and you play with. In my tests, my interpreter have around 18Mb RAM available.
- A small demo is in the bottom of this post.
- SSL Support
- This is the latest addition. Since I cant test all its functionality, I need someone to test it for me. I made a small test where a import socket; hasattr(socket, "ssl")returned "True" so I assumed everything was fine.
Now I will start tracking the released versions using my own version numbers after a _ character.
This new release is named: PSP-Stackless-2.4.4_1.zip and can be downloaded here.
Here are some example apps:
OGG Playback:
import pspogg, psp2d
pspogg.init(2)
pspogg.load('REALTEST.OGG')
pspogg.play()
while 1:
pad = psp2d.Controller()
if pspogg.endofstream() == 1 or pad.cross:
print pspogg.getsec()
print "end of stream"
pspogg.end()
break
print "exit"
MP3 Playback:
import pspmp3, psp2d
pspmp3.init(1)
pspmp3.load('test.mp3')
pspmp3.play()
while 1:
global lastPad
pad = psp2d.Controller()
if pspmp3.endofstream() == 1 or pad.cross:
print pspmp3.gettime()
pspmp3.end()
break
print "exit"
SSL Support:
import socket
print hasattr(socket, "ssl")
The modules have the following API:
pspogg
pspogg.init(ch) Initializes the OGGVorbis subsystem.
pspogg.load(file) Loads an OGG file.
pspogg.stop() Stop OGG playback.
pspogg.pause() Pauses OGG playback, call again to unpause.
pspogg.play() Play a loaded OGG file.
pspogg.endofstream() Returns 1 if stream has ended.
pspogg.getsec() Returns the stream play time in seconds.
pspogg.getmin() Returns the stream play time in minutes.
pspogg.gethour() Returns the stream play time in hours.
pspogg.volume(vol) Sets the OGG subsystem volume.
pspogg.end() Stops playback and free up used memory.
pspmp3
pspmp3.init(ch) Initializes the MP3 subsystem.
pspmp3.load(file) Loads a MP3 file.
pspmp3.stop() Stop MP3 playback.
pspmp3.pause() Pauses MP3 playback, call again to unpause.
pspmp3.play() Play a loaded MP3 file.
pspmp3.endofstream() Returns 1 if stream has ended.
pspmp3.gettime() Returns the stream play time in format HH:MM:SS.
pspmp3.freetune() Free up used memory and releases MP3 subsystem.
pspmp3.end() Stops playback and calls freetune.
Carlos
carlosedp+themindcaster@gmail.com
As promised, today I will start a series of small tutorials for the Stackless usage.
The examples will be focused on PSP but they can all be implemented for Pygame, just switch the graphic functions in psp2d.
A great package that helps a lot the development is the psp mockup libraries. They mimic the psp2d module and translates them to Pygame. With an installation of Python and Pygame you can test all your programs in PC before putting them in the PSP.
Well, lets start the tutorial, the code is very documented and can be easily understood, if you have any questions, contact me over the commentaries or my email - carlosedp+themindcaster at gmail.com
The full code package can be downloaded here.
The Stackless for PSP can be downloaded here.
# -*- coding: iso-8859-1 -*-
'''
This is an example on using Stackless Python in PSP. The idea is based on a
tutorial created by Sakya.
Here we have the concept of agent based programming where the player, the NPC
and the render engine as an agent doing its actions.
The player agent waits for the user input captured from the keypad.
The NPC agent starts running aroundn the screen in a predefined pattern.
The render engine does all the drawing job clearing the screen and putting each
agent in its own place.
As you can see, all the logic is very simplified because of the flexibility
stackless gives to us. Every agent can have its own behaviour and optionally
follow some "world" rules defined for example in a separate Agent.
This "World" could detect collisions, handle communications between agents and
interact with other elements. This can be an exercise to the user.
'''
import psp2d, pspos
from time import time
import sys
import stackless
# Set processor and bus speed
pspos.setclock(222)
pspos.setbus(111)
# Creates the screen and its background color (Black)
screen = psp2d.Screen()
screen.clear(psp2d.Color(0,0,0,255))
# Loads the font
font = psp2d.Font('font.png')
# Loads the character movement images
spriteImages = []
spriteImages.append((psp2d.Image('amg1_bk1.png'), psp2d.Image('amg1_bk2.png'))) #Direction = north = 0
spriteImages.append((psp2d.Image('amg1_fr1.png'), psp2d.Image('amg1_fr2.png'))) #Direction = south = 1
spriteImages.append((psp2d.Image('amg1_lf1.png'), psp2d.Image('amg1_lf2.png'))) #Direction = west = 2
spriteImages.append((psp2d.Image('amg1_rt1.png'), psp2d.Image('amg1_rt2.png'))) #Direction = east = 3
# Creates the Agent base class
class Agent(object):
def __init__(self):
self.ch = stackless.channel() # Communication channel (not used here)
self.running = True # Flag to control the running status
stackless.tasklet(self.runAction)() # Creates the agent tasklet
def runAction(self):
# Here we define the main action, a repetition of the function self.action()
while self.running:
# Runs the action
self.action()
# Give other tasklets its turn
stackless.schedule()
def action(self):
# In the base class do nothing
pass
class player(Agent):
def __init__(self, rend):
Agent.__init__(self)
self.rend = rend # Reference to the renderer tasklet
self.boolSprite = False
self.direction = 1
self.speed = 3
self.posX = 30
self.posY = 30
self.lastPad = time()
self.rend.agents.append(self) # Adds this agent to the renderer
self.sprite = spriteImages[self.direction][int(self.boolSprite)]
def action(self):
self.sprite = spriteImages[self.direction][int(self.boolSprite)]
pad = psp2d.Controller()
if pad.cross:
print "exit"
self.rend.exit()
elif pad.triangle:
screen.saveToFile("ms0:/PSP/PHOTO/screenshot.png")
elif pad.down and (not self.lastPad or time() - self.lastPad >= 0.05):
#Draw the player facing south:
self.lastPad = time()
self.direction = 1
if self.posY + self.sprite.height + self.speed <>
self.posY += self.speed
self.boolSprite = not self.boolSprite
elif pad.up and (not self.lastPad or time() - self.lastPad >= 0.05):
#Draw the player facing north:
self.lastPad = time()
self.direction = 0
if self.posY - self.speed >= 0:
self.posY -= self.speed
self.boolSprite = not self.boolSprite
elif pad.left and (not self.lastPad or time() - self.lastPad >= 0.05):
#Draw the player facing west:
self.lastPad = time()
self.direction = 2
if self.posX - self.speed >= 0:
self.posX -= self.speed
self.boolSprite = not self.boolSprite
elif pad.right and (not self.lastPad or time() - self.lastPad >= 0.05):
#Draw the player facing east:
self.lastPad = time()
self.direction = 3
if self.posX + self.sprite.width + self.speed <>
self.posX += self.speed
self.boolSprite = not self.boolSprite
class NPC(Agent):
def __init__(self, rend):
Agent.__init__(self)
self.rend = rend
self.boolSprite = False
self.direction = 0
self.speed = 5
self.posX = 230
self.posY = 230
self.lastPad = time()
self.rend.agents.append(self)
self.sprite = spriteImages[self.direction][int(self.boolSprite)]
self.count = 20
def action(self):
# This NPC runs around the screen changing its direction when touches the border.
self.sprite = spriteImages[self.direction][int(self.boolSprite)]
if self.direction == 0 and (not self.lastPad or time() - self.lastPad >= 0.05):
self.lastPad = time()
if self.posY - self.speed >= 20:
self.posY -= self.speed
self.boolSprite = not self.boolSprite
else:
self.direction = 2
if self.direction == 2 and (not self.lastPad or time() - self.lastPad >= 0.05):
self.lastPad = time()
if self.posX - self.speed > 0:
self.posX -= self.speed
self.boolSprite = not self.boolSprite
else:
self.direction = 1
if self.direction == 1 and (not self.lastPad or time() - self.lastPad >= 0.05):
self.lastPad = time()
if self.posY + self.sprite.height + self.speed <>
self.posY += self.speed
self.boolSprite = not self.boolSprite
else:
self.direction = 3
if self.direction == 3 and (not self.lastPad or time() - self.lastPad >= 0.05):
self.lastPad = time()
if self.posX + self.sprite.width + self.speed <>
self.posX += self.speed
self.boolSprite = not self.boolSprite
else:
self.direction = 0
class render(Agent):
# This is the renderer agent
def __init__(self):
Agent.__init__(self)
self.agents = []
def exit(self):
# When the player calls the exit, tell all Agents to stop running
for agent in self.agents:
agent.running = False
self.running = False
def action(self):
# Each frame the renderer clears the screen, writes the text and draws each
# registered agent.
screen.clear(psp2d.Color(0,0,0,255))
font.drawText(screen, 10, 225, "Move your character with directional")
font.drawText(screen, 10, 240, "Triangle takes screenshot")
font.drawText(screen, 10, 255, "Press X to exit")
for agent in self.agents:
screen.blit(agent.sprite, 0, 0, agent.sprite.width, agent.sprite.height, agent.posX, agent.posY, True)
screen.swap()
# Creates the renderer object
rend = render()
# Creates a player Agent
play = player(rend)
# Creates one NPC that runs around the screen
NPC1 = NPC(rend)
# Starts the game loop
stackless.run()
About 3 weeks ago, I got a Sony PSP, since only playing games isnt enought for me, I started fiddling around for so called "Homebrew" software for it.
The homebrew community for PSP is quite big and mostly around C coding but surprisingly I found that a guy named Jerome made Python-psp, awesome port of Python 2.4.3 and PSP graphic, sound and network API to Python modules.
Based on that and my bare knowledge of C, I decided to start working on a Stackless Python port for it.
I recently saw the great work from Richard Tew in porting Stackless to Nintendo DS and decided to give a try. Checked out the 2.4.3 PSP port from python-psp repository and merged the Stackless 2.4.4 tag into it.
The first thing to be done, was fixing up some conflicts mostly related to IO and threads. Next Richard pointed me out that the Stackless needs to save and restore stack pointers and this is done in assembly.
Based on trial and error, it took me a day to figure out and have a compiled interpreter.
To finish it all, I ran the stackless unittests and some Stackless applications from the Stackless Examples Project and found that its all working.
I hope other people could try it out and maybe find some bugs, probably I will make the source available and the diff patches too.
The next thing in my roadmap is porting Python and Stackless Python 2.5.1 to PSP, hope it wont be much trouble.
The download is temporarily stored on Stackless Examples project. As soon as I decide to host it or anyone else do, it will be here:
http://stacklessexamples.googlecode.com/files/PSP-Stackless-2.4.4.zip
To install just create a folder in your /PSP/GAME150 folder and place the EBOOT.PBP there.
The python folder is the libraries and must be placed on your memory stick root.
For more information check the Python-psp page.
Thanks a lot for Jerome for the amazing work on the Python port and Richard Tew for the Stackless porting!
Any questions contact me directly.
In the last days, i've been committed to learn C++ so I can port performance critical methods in my Python apps to it. I found a great site - www.cplusplus.com with a nice tutorial worth a look.
I started reading thru a lot of documentation on how to create Python C modules but all those PyObjects and all made a mess in my head.
Looking in the Python-Ogre (Python bindings for the wonderful Ogre3D engine), I found that they use a new code generator for boost-python called Py++.
I heard a lot about boost and its qualities so I figured out that this was the best option and with Py++ to create the wrapper files it became easier.
The problem was not how to create the wrapper files and generate the modules but and install that bunch of packages and modules on windows was a pain.
What you will need:
- Compiler (I'm using VS2005 Express since its free)
- Platform SDK R2 (Windows headers)
- Python (Of course...)
- 2 eggs ... oops... forget this one
- Boost installer for Windows Easier to install, better than compile yourself.
- GCC-XML
- Pygccxml
The resumed installation procedure is:
- Install the compiler and the platform SDK
- Configure your compiler to use the 'libs', 'includes' and 'bins' from the SDK
- Configure the vcvars32.bat file to add the SDK paths to it so the Compile console finds the headers.
- Run the boost installer, it will download the needed packages from a mirror. I installed the base packages and the Python lib.
- Unpack and run 'python setup.py install' on GCC-XML. In my case, it have not compiled with VC2005 so I unpacked myself and followed the instructions here. Then I compiled using the generated solution file.
- Install the pygccxml package 'python setup.py build install'
- Install the py++ package 'python setup.py build install'
Thats it for now... in my next post I will post some examples and procedures for generating the C++ modules.
Reading a post from a Planet PythonBrasil blog today, our friend Rodrigo Cacilhas has proposed some approaches on the Oddwords puzzle where the objective is to invert the odd words in a phrase.
The post can be seen here: http://kodumaro.blogspot.com/2007/05/oddwording.html
I created a small solution based on list comprehension and the and-or trick. It´s like this:
text= "abc def ghi"
print " ".join([(x%2 == 0 and y or y[::-1]) for x,y in enumerate(text.split())])
It shows how powerful list comprehensions can be.
Labels: python
First post, new blog.... well, this will be the place where i will write about programming, tech and discoveries I find around the internet.
Keep your eyes here for great content.