sprite palette/index image script

I’ve been using blender to make 2d sprites for simple game projects I’m writing in c++
and I’m a bit lazy so did some searching hoping to find a script that would do the work of putting all the individual animation frames into one big palette/index image.
having no real luck with that I thought I’d take a shot at writing one my self, one of the forum posts said it would be easy, though I’m not sure its exactly the same idea.
http://blenderartists.org/forum/showthread.php?t=119479

from that thread I got a link to a blender python code tutorial site with some code that saves a frame as a png image file but I’m having trouble figuring out how to actually mess with the picture.
I’ve been using http://www.blender.org/documentation/246PythonDoc/index.html and http://docs.python.org/lib/lib.html as references

so if anybody can point me in a direction to search for more information, or any advice I’d appreciate it.

here is the code I got from the website


# --------------------------------
# A trick to save the rendered image png
# --------------------------------
# Workaround to save rendered image to a png file
# (C) 2004 soler jm
# --------------------------------

import Blender 
from Blender import Scene 
SC = Scene.GetCurrent ()
RC = SC.getRenderingContext ()

# --------------------------------
# Get and render change the directory name
# Recover and change the directory rendering
# --------------------------------

MYDIR = '/ test /'
RENDERDIR = RC.getRenderPath ()
RC.setRenderPath (RENDERDIR + MYDIR)

#------------------------------------
# Curiously there is no function:
# GetImageType but this way
# East on the image format saved
# Is well static and not a format
# Animation
# ----------
# Curiously there is no getImageType
# But like that you can be sure that
# Images are in a static type not in a
# One Movie
#------------------------------------

IMAGETYPE = Blender.Scene.Render.PNG
RC.setImageType (IMAGETYPE)

#------------------------------------
# Hold on the animation on a single image
#------------------------------------

NEWFRAME = 12
OLDEFRAME = RC.endFrame ()
OLDSFRAME = RC.startFrame ()
RC.startFrame (NEWFRAME)
RC.endFrame (NEWFRAME)

#------------------------------------
# Renders
#------------------------------------

RC.renderAnim ()

# --------------------------------
# Now there is a file "0012"
# In the directory "/ render / test /"
# But without extension is needed
# Add almost by hand
# ------
# Now there is a new file "0012"
# In the "/ render / test /" directeory
# But without extention
# So we have to rename the file.
# --------------------------------

import os

FILENAME = "% 04d"% NEWFRAME
FILENAME = FILENAME.replace ( '','0 ')
FILENAME = RENDERDIR+MYDIR+FILENAME

try:
    TRUE = os.stat (FILENAME)
    os.rename (FILENAME, FILENAME + '.png')
except:
    pass

#----------------------------------
# return to te original frame values # Return to te original frame values
#----------------------------------

RC.endFrame (OLDEFRAME)
RC.startFrame (OLDSFRAME)

#----------------------------------
# return to te original render dir # Return to te original render dir
#----------------------------------

RC.setRenderPath (RENDERDIR) 

I had to make some minor modifications because of difficulties copying the code, and it seems import nt/posix don’t work anymore, replaced by import os it seems?

I can’t help you, honestly, but I’d be very interested to know more about your project. I’m learning C++ right now with the goal of making a Pixel Art app and eventually a 2D platformer. I know what you’re trying to do, but I’ve no Python knowledge at all. Depending on the size of the sprite you’re making, tho, I am wondering if it might not be easier to make the sheet manually. I’m just thinking that there might be alignment issues if you do it this way, and that might negate whatever automation you come up with by forcing you to go in and tweak the sheet afterwards.

With something like Graphics Gale you can layout a 32x32 or whatever grid you’d like and line up all your sprites on whatever size sheet you’d like. Unless you’ve got dozens and dozens of frames per character to layout, I don’t imagine it would take too long to do it manually (maybe a day at the most?).

Anyway, like I said, I’d be interested in your project. I’m into pixelart and 2D games in general :stuck_out_tongue:

Have a look at the Blender.BGL submodule in the Python API docs. I think you’ll find everything you need there to build the multi-image image using OpenGL.

How to save it afterwards though… that may be the trick.

I think I had parts of a similar script laying around somewhere. I had planned on using Blender to make sprites for a GBA game, but soon just resorted to doing it by hand. I’ll see if I can dig it up later today, and see if it still works or not. If not I’ll try to fix it up and post it.

For lining up/combining images with a script, you can just use an Image object, and then save it to file. No need to mess with OpenGL at all.

Yes but there are no blitter operations in the Image object. There must be a more efficient way.

I guess if you really wanted to do it via OpenGL you could just blit the bitmaps to the default script surfaces and then use a glReadPixels call. I’m not sure how you would convert that image to something you could save from within Blender python, though, without expressly using the Image class. At that rate, the most efficient way would be to just use a Image class from the start. That is, unless you just write a raw bitmap yourself straight from the buffer object, but even then your still going to have to loop through the buffer to write it.

Yes, as I said saving will be the issue if OpenGL is used (for obvious reasons). But there are a number of libraries out there that can take the output of glReadPixels() and save it into a number of different image types. I’d be surprised if there wasn’t something available for Python.

I do, however, tend to agree with the suggestion that it’s probably more trouble than it’s worth since there are also several programs out there that will stitch images together into a single image.

thanks for the advice guys
I’ve been going over the module docs and searching google and I can’t for the life of me figure out how to get access to the rendered image in python short of loading it from a file.
I don’t know if I’m missing something obvious, subtle or if its simply impossible.
though its probably largely due to my lack of python experience, I may have bitten off more than I could chew.

as for my c++ work, I’m still learning the basics, my friend pointed me to Microsoft’s dark gdk, I’ve been looking into crystal space but for the most part I haven’t made anything yet, I’m working on a very simple top scrolling shooter game for starters

There is a script like the proprietary one from your first post was made for the FIFE engine (I couldn’t find it). They might have what your looking for or are working on it, just shoot them a letter and ask.

As of more recent versions of Blender (don’t know the exact version), the most recent result is stored in an image called ‘Render Result’.

To get it, all you have to do is:


import Blender.Image

img = Image.Get('Render Result') #Most recent render result

Note that it’ll be overwritten every time you render, though, so manipulate it (or save it to a different image object), before re-rendering.

Edit:

While testing, it seems that this Image object doesn’t have pixel data we can access via Python. For now, the only access method may in fact be to load it from a file.

Edit 1:

Found the code and cleaned it up/made it a little more ‘average person’ usable. It won’t move along the z axis (like in a sphere), since I never decided I needed it. I’ll clean it up later this weekend and release a ‘user friendly’ version (probably a little faster, not that this is particularly slow). It has some code issues with things not being in ‘proper’ form I suppose, but it works…

If you play with it some, you should get the idea:


import Blender
from Blender import BGL, Camera, Constraint, Image, Mathutils, Object
import bpy

try:
    import math
except:
    print 'A full python install is required to run this script'

####################################
#
#    User Params
#
####################################

# Object to Track To (for camera to follow)
trackOb = 'Suzanne'

# Path to render file, excluding filename
renderPath = '/users/yourusername/temp/'

# Filename to render to
filename = 'temp.png'

XYSteps = 4 #Number of steps in the x-y plane
YZSteps = 1 #Number of steps in the y-z plane

startLoc = Mathutils.Vector([4, 0, 1])


#####################################
def blitImage(dest, source, start):
    sourceSize = source.getSize()
    for i in xrange(sourceSize[0]):
        for j in xrange(sourceSize[1]):
            dest.setPixelF(start[0]+i, start[1]+j, source.getPixelF(i, j))

class SceneObject(object):
    def __init__(self, scene):
        self.scene = scene
        
    def addToScene(self, data, name):
        self.ob = self.scene.objects.new(data, name)
        return self.ob
    
    def removeFromScene(self):
        self.scene.objects.unlink(self.ob)
        
    def setLocation(self, loc):
        self.ob.setLocation(*list(loc))
    
class TrackedCamera(SceneObject):
    def __init__(self, scn, type):
        SceneObject.__init__(self, scn)
        
        self.__cam = Camera.New(type, 'TrackedCam')
        self.__camOb = self.addToScene(self.__cam, 'TrackedCam')
        
    def __del__(self):
        self.removeFromScene()

    def trackToObject(self, object, track = Constraint.Settings.TRACKNEGZ, up = Constraint.Settings.UPY):
        con = self.__camOb.constraints.append(Constraint.Type.TRACKTO)
        con[Constraint.Settings.TARGET] = object
        con[Constraint.Settings.TRACK] = track
        con[Constraint.Settings.UP] = up
        
    def makeActive(self):
        self.scene.setCurrentCamera(self.__camOb)
        
########################################
scn = bpy.data.scenes.active

TWOPI = 2*math.pi

xyStepSize = TWOPI / XYSteps
radius = startLoc.magnitude
        
tc = TrackedCamera(scn, 'persp')
ob = Object.Get(trackob)
tc.trackToObject(ob)
tc.setLocation(startLoc)
tc.makeActive()

curXYTheta = 0
rc = tc.scene.getRenderingContext()
xR = rc.imageSizeX()
yR = rc.imageSizeY()
rc.setRenderPath(renderPath)

imageSave = Image.New('Output', xR * YZSteps, yR * XYSteps, 32)

curXPix = 0
curYPix = 0

for i in xrange(YZSteps):
    zLoc = startLoc[2]
    for j in xrange(XYSteps):
        xLoc = radius * math.cos(curXYTheta)
        yLoc = radius * math.sin(curXYTheta)
    
        tc.setLocation([xLoc, yLoc, zLoc])
        rc.render()
        
        rc.saveRenderedImage(filename)
        
        rend = Image.Load(renderPath+filename)
        rend.reload()
        
        blitImage(imageSave, rend, [curXPix, curYPix])
            
        curXYTheta += xyStepSize
        curYPix += yR
        
del tc
imageSave.makeCurrent()
Blender.Redraw(-1)

I’d like to get rid of the math module import (I like to keep it all in the Blender family, so to speak), but I guess that may not be possible without some slower workaround.