Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

Spritely -- a simple image editor
  • MarkMark
    Posts: 1,019

    I'm still scratching my head over the best approach to print, but this version does generate simple set statements to draw an image. I'm hoping to get more functionality into it soon.

    Draw your sprite in the grid on the right, then copy the text from the output box to get the code to paste into your program.

    http://devilstower.posterous.com/spritely-01-codea-sprite-editor

  • This is really cool! The space in bottom right could be used to display a palette, so that you can reuse colors.

    (BTW, the order of blue and green seems to be reversed in drawBig.)

  • This is awesome. 8-bit Art in codea. yeah!

  • SimeonSimeon
    Posts: 3,449

    Fantastic work Mark. I love that you put sound effects in for painting, and that you seem to have built the UI icons in your own editor, nice touch :)

    Regarding getting the data back out of the editor, there's a new, undocumented function in 1.2 you can use to make this awesome.

    loadstring() will let you execute a chunk of Lua code. So you can do the following instead of printing the text to the output window.

    • Store the image creation code as a big string using the custom data storage. Do the following: saveProjectData( "SpritelyData", "lots of image code as a string" )

    • The "lots of image code as a string" data would look something like this:

    local spritely = image( 16, 16 )
    spritely:set( 1, 4, 244, 100, 16 )
    spritely:set( 2, 4, 244, 100, 16 )
    spritely:set( 3, 4, 244, 100, 16 )
    spritely:set( 4, 4, 244, 100, 16 )
    -- ... and so on
    return spritely
    
    • In order to create an image from this saved data, all the user has to do is the following:
    createImage = loadstring( readProjectData("SpritelyData") )
    
    myImage = createImage() -- executes the above code
    
    sprite( myImage, x, y ) -- render image
    
    • Bonus points if you can allow the user to customise the name that spritely saves the data under (instead of "SpritelyData"). The user can have a quick way to create images from Spritely's saved data.

    Note: sprite editing is actually a feature I've wanted to add to Codea for a long time, and still might add.

    One way to allow the user to store the data under their own key could be to do the following, print something like this to the output window:

    -- Copy this data into your own sprite with the following code
    saveProjectData( "YOUR SPRITE NAME", readProjectData( "SpritelyData" ) )
    
    -- Load your new sprite into an image
    -- (Note the function call braces at the end of the line)
    myImage = loadstring( readProjectData( "YOUR SPRITE NAME" ) ) ()
    
  • I wrote a little Python script which uses PIL to convert an image file to a series of "anImage:set(...)" statements: http://szleski.posterous.com/images-in-codea That way we can bundle custom sprites with a Codea project.

    Example: python image2codea.py image.png

    Output: image.lua

  • ruilovruilov
    Posts: 446

    Plus one for this

    How fast is codea in drawing images?

    The code i've been working on (pacman) requires drawing optimizations because i was using rect for drawing pixels, but with the new image functionality i imagine that's not the best way anymore

  • MarkMark
    Posts: 1,019

    New version up that incorporates all these good suggestions.

    -- color palette for some pre-defined colors -- preview of image at actual size -- print to output fixed -- save to project string

    Simeon -- that loadString() function is killer. Solves all manner of problems. And building everything to one big screen and dumping it to print solved the nested loop issue.

    http://devilstower.posterous.com/spritely-020-codea-icon-editor

  • ruilovruilov
    Posts: 446

    Wow so awesome. How about talking to bortels about using his keyboard implementation (dont think he release yet) so you can type the name of the image as you save it?

  • ruilovruilov
    Posts: 446

    i'd also allow currenttouch.state to be Moving as well and remove the old touch check so that the user can draw his finger around to draw stuff

  • FredFred
    Posts: 383

    This is great!

  • BortelsBortels
    Posts: 1,553

    The keyboard class, as it stands (working, poorly, and ugly) is up on github already - https://github.com/bortels/HersheyCodea/blob/master/Keyboard.lua

    If someone wants to clean it up, feel free; I'm happy to accept push patches, or just publish a better one - I'm not proud. The keyboard has been sidetracked while I worked on image() stuff (nearly done, I swear!) and now I'm seriously considering redoing the font stuff I did with images for speed (ie. I'd pre-render the characters and draw them with images, rather than line drawing them each time).

  • SimeonSimeon
    Posts: 3,449

    Regarding drawing speed, @ruilov, Codea is a bit slow with sprites at the moment. We're going to be heavily optimising sprite drawing in the coming releases. noSmooth() rects are probably fastest.

    Are you drawing the level in Pacman as lines at the moment? It would be interesting to see how all the rects() compare to a single image of the level map speed-wise. I've only tried it on iPad 2 and it seemed perfectly smooth.

  • ruilovruilov
    Posts: 446

    pacman map is drawing as rects. Each pixel from the original game corresponds to 2.5 x 2.5 pixels in codea. Drawing the rects for each tile of the game was slow (DeltaTime ~ 0.1) so added an optimization that joins two rects from different tiles if they have a side in common before drawing, which got DeltaTime to 0.02

  • SimeonSimeon
    Posts: 3,449

    @ruilov I suspect noSmooth() line() calls would be fastest, as these use the GL_LINE primitive, which is very cheap. What would be more interesting is to see if an image() with the level pixels set is faster to render using sprite().

    The way you did it is really cool though.

  • MarkMark
    Posts: 1,019

    -- On @ruilov's suggestion, changed draw to support support MOVING.
    -- Added 1x and 2x views of image in progress.
    -- Added a load / save dialog with slots for multiple saved images
    -- general cleanup

    I'm looking at Bortels's keyboard class, but thought the load/save dialog would help till I get it working.

    http://devilstower.posterous.com/spritely-030-simple-image-editor

  • SimeonSimeon
    Posts: 3,449

    Nice improvements. This is really amazing, nice features. I think it looks better with noSmooth() used in certain places - and runs faster. I modified the following functions:

    noSmooth() on scaled sprites uses nearest-neighbour interpolation, so you get a nice pixellated effect on the 2x sprite preview, rather than a blurriness. The noSmooth() on the main grid makes interaction faster, and looks much cleaner, I think.

    drawBig() and drawSmall() to incorporate noSmooth() as follows

    drawBig:

    function drawBig()
        pushStyle()
        noSmooth()
    
        -- ...original drawBig() code, except change 
        strokeWidth(1) -- thinner strokeWidth looks good with noSmooth()
    
        popStyle()
    end
    

    drawSmall:

    function drawSmall()
        pushStyle()
        noSmooth()
    
        strokeWidth(1)
    
        -- ...original drawSmall code up to:
    
        sprite( anImage, x, 412 )
        sprite( anImage, x + 1, 312, SpriteSize * 2, SpriteSize * 2 )
    
        popStyle()
    
        -- Draw the numbers with smooth() style
    
    end
    
  • SimeonSimeon
    Posts: 3,449

    Also, the load / save dialog box is excellent. I would also use noSmooth() on the preview images for each slot.

    The icons confused me initially, I thought the blue down-arrow was "Save" but it seems to be load. Perhaps you could use an "L" and an "S" on these icons as well.

  • MarkMark
    Posts: 1,019

    The noSmooth() really does crisp things up. Nice.

    Down arrow should be save and up arrow load. If it's not working that way, I've mucked up something.

  • SimeonSimeon
    Posts: 3,449

    With 1.2.5 you will have to flip your images (previews and saved results), as image coordinates now start in the bottom left.

  • ruilovruilov
    Posts: 446

    @Simon it's funny. The print button is now a fax machine

  • SimeonSimeon
    Posts: 3,449

    @ruilove THAT'S why I was confused about the save and load buttons :) @Mark - they were the right way around, I was just running your editor on a build of 1.2.6 and forgot the images would be upside down.

  • MarkMark
    Posts: 1,019

    Yes, I should have realized that when you talked about a blue down arrow that you were using the update image format.

    This one should include noSmooth & have images flipped. I kept my internal grid top-left based and just modified the spots that translate between grid array and image.

    http://devilstower.posterous.com/spritely-040-simple-image-editor-19454

  • The new version is awesome! Thanks for sharing this!

    I have one issue with the palette: when a color from palette is chosen the sliders no longer show correct values of RGBA. I guess this is how the iparameter's work when the variable value is changed in the code. I'm not sure how one could fix it.
  • MarkMark
    Posts: 1,019
    Yeah, I can't think of any way to address this. I tried recreating the Iparameter after each color selection, but the sliders are unaffected.

    I've made a small update that adds a "global" button. This button saves the current image to global data rather than Spritely project data. Also included is a sample SpritelyLoader class to grab the global data and move it to your project.

    The set of images in the save / load dialog are saved to project data, so you'll need to shuffle globals over one at a time, but it beats copy/pasting the data in.

    http://devilstower.posterous.com/spritely-050-simple-image-editor
  • One way would be to implement custom sliders, maybe as here:
    http://szleski.posterous.com/hslider
    but where to place them? Either on top, or use full screen mode and place sliders on the left (there is no way then to copy output - but maybe it is not needed anymore?).

    BTW, I can't get watch() to work with object's attributes - watch("ss.val") does not work as expected.
  • As far as I understand it, watch only works on global variables. I iften watch("debug") and then set debug to mirror whatever I'm currently interested in.

  • (There's another example of my "i"-"o" displacement on an iPad keyboard.)

  • ruilovruilov
    Posts: 446

    Hey Mark, I merged spritely into an UI framework that I put together. Hope it's useful.

    Edit: http://ruilov.posterous.com/spritely-in-sup-01

  • VetieVetie
    Posts: 7

    Could someone post a simple program that uses Spritely to draw ( a simple box) and then uses spiritely loader to get that data into the project. I did read the comments and looked at the code for invaders but couldn't put everything together to get in working in my test program. I'm just trying to learn the program TIA

  • MarkMark
    Posts: 1,019

    There are basically four steps.

    1) draw the icon in Spritely and save it to global data by touching the globe icon. (you should hear a little whistle to let you know it worked)

    2) copy the text of the SpritelyLoader class into your project.

    3) create an instance of the SpriteLoader class in the setup of your main file. For example:

    myLoader = SpritelyLoader("bob")

    Now run your project. This will take the icon from the global data and save it in your project data under the name "bob."

    Once you've done this, you should remove the reference to the loader from your code. In fact, if you only want to load a single icon, you can now do away with the whole SpritelyLoader class. I know you can't see anything yet, but the loader's job is done.

    4) Now to display your icon. To do this, you'll load it into a string, and execute that string to build the image.


    createImage = loadstring( readProjectData("bob"))
    anImage = createImage() 

    You still can't see anything? That's okay. You need to add one more line to the draw() function of you project's main file.

    sprite(anImage, 100, 100)

    Now! The image stored as bob and rendered in anImage should finally be on the screen.

    Sorry that it's more than a bit awkward. As Codea goes forward, I'd bet we'll find it easier to save images and to move them between projects. When we do, I'll update Spritely.

  • VetieVetie
    Posts: 7

    Thank you very much Mark, this is what I was looking for! Keep up the fantastic work!

  • I'm sorry but I still can't quite figure out how to get the sprite into my project. I'm not sure if I followed the directions wrong? Is there a simpler way??

  • MarkMark
    Posts: 1,019

    You could try just reading the image from the global data. Paste this into the draw() function and see what you get

    createImage = loadstring( readGlobalData("SpritelyGlobal"))
    anImage = createImage()
    sprite(anImage,100,1o0, 32, 32)

  • Do I need to have the Spritely Loader code in my project as well?

  • Never mind, got it working. However, I have a question. The sprite appears tiny, is there a way to enlarge it?

  • SimeonSimeon
    Posts: 3,449

    Render with sprite( image, width, height )

    Change the width and height to something larger. If you just specify the width, the height will be computed to preserve the aspect ratio of the image.

    If you turn on noSmooth() the image won't blur when it is upscaled.

  • How do you turn on noSmooth(). Sorry, I am a total beginner. First time ever coding

  • MarkMark
    Posts: 1,019

    Just add noSmooth() to the draw() function (or setup) before you draw the sprite.

  • Ok. Thx. Love your program it works great. I'm working on merging it with Lua Jump so you will first draw your character and then begin the game.

  • JohnJohn
    Posts: 306

    Made a picture of bender with it: http://yfrog.com/z/hs33nhp

    Bender

  • MarkMark
    Posts: 1,019

    Clearly you must go on to build a game in which Bender steals cigars and beer -- after all, dont forget the one commandment: god needs booze!

    Nice to see the this thing being used. Good work.

  • JohnJohn
    Posts: 306

    That sounds like fun, just got to finish Crabitron first :)

  • MarkMark
    Posts: 1,019

    A minor update. I was creating some icons for... let's just say a game in which a chubby guy in coveralls jumps over things, and it became clear that being able to mirror and image image would be nice (so you don't have to draw both left and right facing versions of asymmetrical sprites). So I added a tool that does just that.

    I also changed the way the flood tool works. It occurred to me that it was kind of worthless the way it was, so I changed it to flood only blank pixels. Not sure that's much better. I may change it to do color-swapping instead.

    Did some general clean up and minor cosmetic adjustments.

    http://devilstower.posterous.com/spritely-060

  • BortelsBortels
    Posts: 1,553

    Heh - I had to ask myself just that question (I just did a flood fill for my Pic library) - I suggest you make it flood fill pixels of the same color where you tap, ie. pick it, then tap a square - and it flood fills from that square out over all pixels of the same color. So you could change Bender's eyes above from yellow to red in two taps.

  • BortelsBortels
    Posts: 1,553

    PS. I love the sample icons you have in there. :-)

  • I still haven't fixed the fact that the save and load arrows appear to be facing wrong way. Until a new release comes out this is relatively easy for people to do: under main add this saveBtn = Button(700, HEIGHT - 200, 5)     loadBtn = Button(700, HEIGHT - 250, 3) instead of what is there for the saveBtn and loadBtn. All this does is switch the icons so that the save one will be where load goes and load will be where save goes making them face the right way since the pushing of buttons is really just touching that part of screen regardless of wheter or not the correct button is there. Hope this helps!

  • *u still haven't fixed, my bad not I :)

  • MarkMark
    Posts: 1,019

    Have you upgraded to Codea 1.2.5? If so, the save arrow should be pointing down and the load arrow should be pointing up. To my mind, that was the "right" way... though I suppose that's open to interpretation.

  • Just got a chance to grab this. Thanks so much for it.

  • MarkMark
    Posts: 1,019

    Thanks. I'm trying to think of what else would be nice here. Maybe buttons to nudge the image one pixel when it turns out your design started just a smidgen off?

  • SimeonSimeon
    Posts: 3,449

    Not sure if these would be useful, but here are some ideas:

    • An invert tool (just do {255 - r, 255 - g, 255 - b, a} for each pixel)
    • A box blur - a simple blur that averages pixels
    • Hue shift slider - rotates your colours through different hues (affects all pixels in the sprite). This would be handy for making colour variations of a particular icon.
    • Saturation slider (affects all pixels in the sprite)