SpriteSheetApplicationSAB

From The Battle for Wesnoth Wiki


This page is related to Summer of Code 2014
See the list of Summer of Code 2014 Ideas



This is a Summer of Code 2014 student page


Description

Aishiko GSOC 2014 SpriteSheets

My proposal is to take the current functions for drawing sprites and move it to allow for spritesheets, while hiding any of the changes from campaign designers. It should allow for the seemless intergration of spritesheets and allow for a period of conversion from multiple files to sheets.

IRC

Aishiko, Aishiko_laptop

Patches

Pull Request 119 Pull Request 130

Proof of Concept

https://github.com/Aishiko/getSprite

This is not quite done, its still rigid and inflexiable to meet our artists needs, however that can be fixed. It also doesn't send an error code and needs to be tested. It relies on all the images in row being the same height and each column being the same width was the plan but it really should be fine with varying widths I think. All the images need to be pressed right up to each other, with borders of 1 pixel in width all around them. The first row needs to be blank put for pixel 0,0 for that contains the border colour and then Row1 HAS to start at pixel 1,0. Otherwise its fine. Ohhh and all it does is FIND the images and returns a std::vector<SDL_Rect> it doesn't actually do anything with them, no handling of malformed sheets, and no error codes or logging (though there is a place for it it just currently contains a comment).

However I see this as becoming a powerful tool that devs that can compile wesnoth can compile as well, and as a standalone, it means the artists that don't mess with the code do not have to compile wesnoth once fully implemented.

Implementation Ideas

Goals

Eliminate as many small single images as possible from the program. Enable Sprite Sheets to be used in;

  1. Gameplay
    • Units
    • Terrain
    • etc
  2. Menus, mouse pointers, etc. Optional Goal I doubt at this point that I'll make it this far.
  3. Reuse as much as the existing syntax as possible
  4. Create Unit Tests to make sure that the areas modified are as good as I can make them.
  5. Make it easy for the artists to add sprites to a sprite sheet:

Problems

  • Not all units and terrain are 72x72
  • Adding a boarder around each image to make it easier for the artists to see what sort of space they have to work with will make taking the current images and converting them a bit harder as well as creating a script to convert them (which remains a soft goal, ie if I have to do it AFTER the summer, I'll do that.) Stupid perfectionist leanings, at least for what I think of to get the project ready!
  • Syntax making sure that its easy to use and understand for the average user

First Steps

I will create a test program that will allow me to make sure that the sprites are being parsed properly. I'll need a spritesheet for this, preferably a big one. Through this whole process if it breaks it should only break on the sprite sheets until then it shouldn't break anything exisiting.

Cache

In cache the spritesheets need to be parsed, either all at once or only those grids that are currently needed and the found corners saved as above. When an image is needed from a spritesheet it will gotten out of the sheet and then passed into the cache that will using and holding that image such as the scaled_to_zoom_ or tod_colored_images_. The sheets will remained cached until the game is exited completely or the cache is full the oldest referenced image will be dropped.

The Plan

How This Will Work

The way this will work is each sheet will be a grid of one colour that is not used in any of the sprites (say a shade of pink) this RGBA colour is a Primary Key, it will lay out a grid of areas within our spritesheet. Then each of those grid squares (or rectangles) each frame/image has a second border of colour, say a different shade of pink. Each unit's spritesheet will then be read at loading into the cache, each grid square will be searched for an image if found it will be loaded into an object that will contain the following information:

  • SpriteSheetName
  • Row
  • Column
  • Upper Y
  • Upper X
  • Lower Y
  • Lower X

Each sprite will be returned as a SDL_Rect in a vector, that vector will be named whatever the unit is.

WML

Each Spritesheet will have a Spritesheet set of tags in the unit config file, it will look something like:

[Spritesheet]
    File=file_path/name.png
    [Image]
        ImageID=1
        ImageName="Attack_1"
        Upper_X=x
        Upper_Y=y
        Lower_X=x
        Lower_Y=y
    [/Image]
    -- More Images here
[/Spritesheet]

OR

[Spritesheet]
    File=file_path/name.png
    [Image]
        ImageID=1
        ImageName="Attack_1"
        Coordinates=[x,y,x,y]  --upper followed by lower x,y
    [/Image]
    -- More Images here
[/Spritesheet]


Each animation sequence called by doing a call like:

$Elvish_Sorceress[1~10,1,2]:[80*5,100*2,80*5] or <Elvish_Sorceress>[1~10,1,2]:[80*5,100*2,80*5]

Almost like a normal call but to a single image file instead of several files. Out of the Elvish_Sorceress.png, images 1-10 and then 1 and finally 2 are called for the attack sequence in this case.


The current syntax is:

image="units/elves-wood/sorceress-melee-attack-[1~10,1,2].png:[80*5,100*2,80*5]"

I envision it to be more like one of these to work as with a spritesheet:

<image>[1~30][80*5,100*2,80*5]", which expands to <image>1:[80],<image>2:[80],<image>3:[80],etc

or

$image[2.1~2.10,2.1~2.2]:[80*5,100*2,80*5]

This should take the current markup language and merely extand it to allow for calling an SDL_Rect from the spritesheet. The <sheetName> will either relate to a memory address of the sheet or to an image under units/ like units/Elvish_Sorceress.png

When the WML goes for the individual images that create that animation it'll look at the generated Autogenerated Spritesheet WML added to each. The idea of holding a config of where each image is located and saving that would remove the overhead of searching everytime a frame is called. These frames would then be passed to the normal cache used and stored there, until they expire.

Making WML Painless

I'll implement a standalone tool that will take 1 or 2 inputs, if 1 just the spritesheet it will then find each image and ask the user to define the image (attack_1 etc) it will then generate a barebones spritesheet config file to be appended to the unit.cfg. If 2 it will take the old unit.cfg, and look for NEW images and REMOVED images, and only add or remove those changed so it doesn't require the user to double check or change image numbers by 1 or 2 everywhere to make adding/removing/changing an image so painful they don't want to do it.

Spritesheet Details

Each Spritesheet will have each unit outlined in a box (Colour and size matters not in this version unless we want to implement a side program that will parse out the correct information for the artists.)

On loading an image if the [SpriteSheet] tags are found then it will automatically check for each called image within the spritesheet's definition pulling out the requried frames as needed. This method will require no more parsing overhead then the usual requirements of parsing the data in the config (IE no need to "scan" the image file looking for grids or borders or anything like that. The spritesheet can be packed as tightly as desired by the artist, and even notes left in the file, such as a block of text that says "Attack animation here". Each unit can have more then 1 spritesheet however, they can only have 1 image with an ImageID, this is unique to the unit not the spritesheet file.

Testing

Phase One

I will create a test program that will allow me to make sure that the sprites are being parsed properly. This program will be intergrated and become the spritesheet core of the program. Having this out by itself will allow me to see what sort of difference there is when parsing just the needed gridboxes and the whole sheet. This will allow me to come up with some decent error messages for malformed sprite boxes.

Phase Two

In addition to creating unit tests, I'll try out various hardware to see what sort of performance changes I can detect during the course of getting things working. I'll test on a Quad-core with 8 or more GB RAM, a Dual-core with 4GB RAM, and a 32bit single core with 1-4 GB RAM (I don't have any Macs so I can not test on that and I only have Windows in a VM, so most testing will be done under Linux I'll depend on the various developers that use windows to let me know how it is affecting the running under Windows & Macs)

Deliverables

Status Requirement Level Number ID Goal Defined
Required 1A Properly working Spritesheet cache to speed up loading and elimnate glithy and laging animations do to disk access times.
Required 1B dynamic so that low mem devices are not adversely effected.
Plan A Only! 2 Properly parse spritesheets and quickly be able to pass that information on for each frame.
Required 3A Spritesheets that are flexible and easy for artists and WML users to implement.
Required 3B Spritesheets that do not have a fixed size for every frame they hold.
Plan A Only! 3C Nor a Fixed grid size that holds each frame in its border.
Plan A Only! Optional 3D Not require to have the gridlines or the borders be a particular width (optional, could be axed for performance reasons).
Plan B Only! Optional 3D Not require the borders be a particular width.
Required 4 WML syntax for Spritesheets that is not long, complex, hard to understand, or prone to errors.
Required 5 No negative or negible impact on loading times

Packages Required

Package Name Reason Status
SDL Needed for getting the colour information Plan A required otherwise Not needed
Boost Might be able to provide a performance boost (no pun intended) Optional

13 Week Timeline

Status

Start/End_Dates

Goals

Current March 20 - April 20:
  • Get more details and further flesh out the details of proposal. Create more patches (at least one every 1-2 weeks that is some bug or feature request, something not trival).
  • Get more familiar with Git and GitHub. Be active in the community and encouraging to others that want to create a patch.
Next April 21 - May 18:
  • More details hammered out and continue doing what I'd been doing during Mar 20 - April 20. Perhaps begin a little pre-coding to test theories.
May 19 - June 1:
  • Add a cache for just the spritesheets
    • Here I'll add a spritesheets cache it will be the cache that will hold all the sprite sheets once loaded. It will have to be felxible (in size and what's loaded) and perstant.
June 1 - 15:
  • Add a get_spritesheet_frame function to get the image of the sprite we need right now.
  • Start on the program to generate the WML spritesheet Code.
June 16 - 29:
  • Implement new WML snytax for the spritesheets.
  • Continue on the program to generate the WML spritesheet Code, and have ready to go.
June 23 - 27:
  • Mid-term evaluation, I would like to receive feedback before this point so that if I'm not performing up to par I can work harder/longer.
June 30 - July 13:
  • Modify any existing functions that need to be modified to handle sheets that broke.
July 14 - 27:
  • Run tests and see what breaks and fix what broke
    • Unit tests would have to be added and commited to keep this up and make sure its as robust as I can make it in the timeframe allotted to make it all work.
July 28 - Aug 10:
  • Pad time in case something takes longer then expected
    • Something ALWAYS takes longer then expected or breaks in ways that we didn't expect and only a fool doesn't plan for the worst, so that is what this is, this is my, "OH CRAP" time. Where I have some time to address the parts that take longer or where I work on optional extended tasks like writing a shell/python script to convert all the images to spritesheets.
Aug 3:
  • End of all major code additions/changes, begin of code clean-up and Minor fixes begin.
Aug 11 - 17:
  • Documentation and clean up anything that hasn't yet be done.
Aug 22:
  • Final evaluation and send the required code snippets to Google.

The Weeks in the Program

Week  1:		May 19 to May 25
Week  2:		May 26 to June 1
Week  3:		June 2 to June 8
Week  4:		June 9 to June 15
Week  5:		June 16 to June 22
Week  6:		June 23 to June 29
Week  7:		June 30 to July 6
Week  8:		July 6 to July 13
Week  9:		July 14 to July 20
Week 10:		July 21 to July 27
Week 11:		July 28 to August 3
Week 12:		August 4 to August 10
Week 13:		August 11 to August 17

Optional tasks if everything goes smoother and easier then planed in no particular order:

  • Convert all the sprites, update all the .cfg for the base units
  • Create script to allow Addon Artists convert their sprites

Artists Weigh In

OK, not just for artists, go to http://forums.wesnoth.org/viewtopic.php?f=9&t=40191 and weigh in on the details that effect you as an user! And only those details, and thank you for helping me make Wesnoth a little bit better.

Current Thoughts

To Happygrue

In implementing the spritesheets I am considering storing a vector with the SDC_Rect info (IE {x,y,h,w}) so that when image 5 is needed it pulls out element(5) or element(-1) if the sprites are numbered from 1 instead of 0. My plans for making this work are to create a spritesheet namespace and then when pulling out an image pass the surface (res) into the images_ cache where it will be handled as if it where a single image taken from the disk. In this way I won't have to change anything about how the images are handled for zooming, colouring, etc. But I'm finding that I really should work on getting the WML and parsing of the lua files done first.

I think going with the following tags would be a good way to go;

[Spritesheet]
   File=file_path/name.png
   [Sprite]
       SpriteID=1
       SpriteName="Attack_1"		this an optional feild
       Location=[x,y,w,h]
   [/Sprite]
   -- More Images here
[/Spritesheet]

This differs from the proposal in that the [Image] tag already exists for another purpose, so I changed it to Sprite and changed the rest to match (uniformity and descriptive too) and Cooridante/Location now basically returns an SDL_Rect. [Frame] tags are also already taken in the animation section.

I think that for this to work I need to get the basics in place for the following by mid June.

1) working cache
	a) load the spritesheet into the proper cache
	b) extract and put an unscaled copy into the correct cache (unscaled I think)
2) wml
	a) spritesheet tags 
	b) spritesheet animation syntax
This page was last edited on 23 May 2014, at 01:27.